题解:P8147 [JRKSJ R4] Salieri
前言
数据结构大杂烩。
挺久之前写的题了,当时没写题解,现在补一个。
Solution
发现是多模匹配状物,第一步先建出来 ACAM。
考虑对询问串在 ACAM 上跑一遍,每跑到一个点记一个
注意到询问串长度和不大,而在 ACAM 上走的点又和询问串的长度相关,所以考虑对过程中所有经过的点建立虚树。
虚树建出来后,先从下到上遍历一遍整棵树,处理出来
此时的虚树上,父亲到儿子的一条虚树边表示原树上父亲到儿子这条链上(不包含儿子)上的所有点的
至于没有访问过的那些点,
直接维护
现在考虑对一个
每次判定,遍历一遍整棵虚树。对虚树上的每条边
这个东西可以用一棵主席树维护。
时间复杂度
Code
:::info[代码]
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3f
using namespace std;
class segmenttree{
private:
struct node{
int v;
node *lc,*rc;
node(int _v=0):v(_v),lc(nullptr),rc(nullptr){}
};
vector<node*> roots;
int wL,wR;
void pushup(node *p){
p->v=0;
if(p->lc) p->v+=(p->lc->v);
if(p->rc) p->v+=(p->rc->v);
}
node *Build(int l,int r){
node *p=new node(0);
if(l==r) return p;
int mid=(l+r)>>1;
p->lc=Build(l,mid);
p->rc=Build(mid+1,r);
pushup(p);
return p;
}
node *Modify(int x,int v,int nowl,int nowr,node *p){
node *new_p=new node(p->v);
if(nowl==nowr){
new_p->v+=v;
return new_p;
}
int mid=(nowl+nowr)>>1;
if(x<=mid){
new_p->lc=Modify(x,v,nowl,mid,p->lc);
new_p->rc=p->rc;
}else{
new_p->lc=p->lc;
new_p->rc=Modify(x,v,mid+1,nowr,p->rc);
}
pushup(new_p);
return new_p;
}
int Query(int l,int r,int nowl,int nowr,node *p1,node *p2){
if(l<=nowl&&nowr<=r) return (p1->v)-(p2->v);
int mid=(nowl+nowr)>>1;
int res=0;
if(l<=mid) res+=Query(l,r,nowl,mid,p1->lc,p2->lc);
if(r>mid) res+=Query(l,r,mid+1,nowr,p1->rc,p2->rc);
return res;
}
void Debug(node *p,int l,int r){
if(!p) return;
printf("Now at (%d,%d), Value=%d.\n",l,r,p->v);
int mid=(l+r)>>1;
Debug(p->lc,l,mid);
Debug(p->rc,mid+1,r);
}
public:
segmenttree():roots(0),wL(0),wR(0){}
void build(int l,int r){roots.push_back(Build(wL=l,wR=r));}
int modify(int x,int v,int editversion){
roots.push_back(Modify(x,v,wL,wR,roots[editversion]));
return roots.size()-1;
}
int query(int l,int r,int queryversion1,int queryversion2){
return Query(l,r,wL,wR,roots[queryversion1],roots[queryversion2]);
}
void debug(int version){
Debug(roots[version],wL,wR);
}
}segt;
struct edge{int to,nxt;}e[500010];int head[500010],ecnt=1;
inline void addedge(int x,int y){e[ecnt]={y,head[x]},head[x]=ecnt++;}
struct node{
int ch[4],fail;
vector<int> v;
}t[500010];
int nodecnt;
void acam_insert(string s,int v){
int p=0;
for(char c:s){
if(!t[p].ch[c-'a']) t[p].ch[c-'a']=++nodecnt;
p=t[p].ch[c-'a'];
}
t[p].v.push_back(v);
}
queue<int> q;
void build_acam(){
for(int i=0;i<4;i++) if(t[0].ch[i]) q.push(t[0].ch[i]);
while(!q.empty()){
int p=q.front();q.pop();
for(int i=0;i<4;i++){
if(t[p].ch[i]){
t[t[p].ch[i]].fail=t[t[p].fail].ch[i];
q.push(t[p].ch[i]);
}else t[p].ch[i]=t[t[p].fail].ch[i];
}
}
}
int n,m;
int a[100010];
int fa[500010],siz[500010],dep[500010],son[500010];
void dfs1(int x,int p=0){
fa[x]=p,siz[x]=1,dep[x]=dep[p]+1,son[x]=nodecnt+1;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
dfs1(y,x);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]]) son[x]=y;
}
}
int top[500010],dfn[500010],rnk[500010],dfn_cnt;
void dfs2(int x,int p){
top[x]=p,dfn[x]=++dfn_cnt,rnk[dfn_cnt]=x;
if(son[x]!=nodecnt+1) dfs2(son[x],p);
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==son[x]) continue;
dfs2(y,y);
}
}
int ver[500010];
void dfs3(int x){
ver[x]=ver[fa[x]];
for(int w:t[x].v) ver[x]=segt.modify(a[w],1,ver[x]);
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
dfs3(y);
}
}
int getlca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
if(dep[x]<dep[y]) return x;
return y;
}
int cnt[500010];
void get_cnt(string s,vector<int>&b){
int p=0;
for(char c:s){
p=t[p].ch[c-'a'];
cnt[p]++,b.push_back(p);
}
}
void remove_cnt(string s){
int p=0;
for(char c:s){
p=t[p].ch[c-'a'];
cnt[p]--;
}
}
int newfa[500010];
int main(){
cin.tie(0)->sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++){
string s;int v;cin>>s>>v;
acam_insert(s,i);
a[i]=v;
}
build_acam();
for(int i=1;i<=nodecnt;i++) addedge(t[i].fail,i);
segt.build(1,1000);
dfs1(0);
dfs2(0,0);
dfs3(0);
memset(head,0,sizeof head);
ecnt=1;
memset(newfa,-1,sizeof newfa);
while(m--){
string s;cin>>s;
int k;cin>>k;
vector<int> b;
get_cnt(s,b);
sort(b.begin(),b.end(),[&](const int x,const int y){return dfn[x]<dfn[y];});
b.erase(unique(b.begin(),b.end()),b.end());
vector<int> c;
c.push_back(0);
c.push_back(b[0]);
for(int i=1;i<(int)b.size();i++){
c.push_back(getlca(b[i-1],b[i]));
c.push_back(b[i]);
}
sort(c.begin(),c.end(),[&](const int x,const int y){return dfn[x]<dfn[y];});
c.erase(unique(c.begin(),c.end()),c.end());
for(int i=1;i<(int)c.size();i++) newfa[c[i]]=getlca(c[i-1],c[i]);
sort(c.begin(),c.end(),[&](const int x,const int y){return dep[x]>dep[y];});
for(int x:c) if(newfa[x]!=x) cnt[newfa[x]]+=cnt[x];
auto check=[&](int mid){
int ans=0;
for(int x:c){
if(!cnt[x]) continue;
if((mid+cnt[x]-1)/cnt[x]>1000) continue;
ans+=segt.query((mid+cnt[x]-1)/cnt[x],1000,ver[x],ver[newfa[x]]);
}
return ans;
};
int l=0,r=inf;
while(l<r){
int mid=(l+r+1)>>1;
if(check(mid)>=k) l=mid;
else r=mid-1;
}
cout<<l<<"\n";
sort(c.begin(),c.end(),[&](const int x,const int y){return dep[x]<dep[y];});
for(int x:c) if(newfa[x]!=x) cnt[newfa[x]]-=cnt[x];
remove_cnt(s);
for(int x:c) newfa[x]=-1;
}
# ifdef TakanashiHoshino
cerr<<"\nUsed time: "<<clock()*1.0/CLOCKS_PER_SEC<<"s.\n";
# endif
return 0;
}
:::