T1 Censoring
题意:给定n个模式串,在母串S中不断删除n词,输出最后S。先删最早,n词中无子串。
题意眼熟,连题名也眼熟。之前做过的是kmp,无非改到了Trie上AC自动机解决。
建Trie给每个词打标记记录长度,建AC自动机别忘考虑后缀上的标记(abcaca ca),然后跑母串,栈存字符,指针数组存匹配位置,若有标记退栈len...
40min敲完
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<queue> #define MAXN 100005 #define reg register #define F(i,a,b) for(i=a;i<=b;++i) using namespace std; char s[MAXN],w[MAXN],ls; struct Trie{ Trie *son[26],*fail; bool ed; int len; }; int top; char stack[MAXN]; Trie *mc[MAXN]; queue<Trie*> q; Trie *newnode() { Trie *p=new Trie; p->fail=NULL; reg int i; F(i,0,25) p->son[i]=NULL; p->ed=0; p->len=-1; return p; } void in(Trie *root) { reg int i=0,c; Trie *p=root; while(w[++i]) { c=w[i]-'a'; if(p->son[c]==NULL) p->son[c]=newnode(); p=p->son[c]; } p->ed=1; p->len=strlen(w+1); } void AC(Trie *root) { Trie *p=root; reg int i; F(i,0,25) { if(root->son[i]!=NULL) { root->son[i]->fail=root; q.push(root->son[i]); } else root->son[i]=root; } while(!q.empty()) { p=q.front(); q.pop(); F(i,0,25) { if(p->son[i]!=NULL) { p->son[i]->fail=p->fail->son[i]; q.push(p->son[i]); } else p->son[i]=p->fail->son[i]; if(p->son[i]->fail!=NULL) { p->son[i]->ed=max(p->son[i]->ed,p->son[i]->fail->ed); p->son[i]->len=max(p->son[i]->len,p->son[i]->fail->len); //!!!! } } } } void ask(Trie *root) { Trie *p=root; reg int i=0,c,j; //i=0 eee while(s[++i]) { if(p==NULL) p=root; c=s[i]-'a'; p=p->son[c]; stack[++top]=s[i]; mc[top]=p; if(p->ed==1) //不能清零 { // printf("%d ",i); top-=p->len; p=mc[top]; // F(j,1,top) printf("%c",stack[j]); puts(""); } } } int main() { // freopen("cen.in","r",stdin); // freopen("cen.out","w",stdout); scanf("%s",s+1); ls=strlen(s+1); int n; reg int i; scanf("%d",&n); Trie *root=newnode(); F(i,1,n) { scanf("%s",w+1); in(root); } AC(root); ask(root); F(i,1,top) printf("%c",stack[i]); // fclose(stdin); // fclose(stdout); return 0; }
T2 bzoj4899
期望送命题,而且还没给数据范围...
https://blog.csdn.net/WerKeyTom_FTD/article/details/53026266
省时间放直链
T3 雨天的尾巴
题意:n点树,m次将x-y路径赋z,求最后1~n点各自的最大次数z。
一开始想的带修主席树额,虽然考试时算了下爆空间,但还是打了然后并调不对。
错因:dfs序+差分nc想错了。
正确姿势:树上差分+线段树合并
树上差分:x+1,y+1,lca-1,f(lca)-1 统计子树即实际。
对每个点建权值线段树(动态开点空间O(4mlogn),不然4n^2爆炸),维护权值的最大出现次数和值以便O(1)查。最后dfs回溯合并查值即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #define MAXN 100005 #define awsl 50 #define reg register #define F(i,a,b) for(i=a;i<=b;++i) using namespace std; queue<int> q; struct R{ int u,v,next; }r[2*MAXN]; struct ASK{ int x,y,z; }ask[MAXN]; int fir[MAXN],lc[awsl*MAXN],rc[awsl*MAXN],tot,siz[awsl*MAXN],ans[MAXN],num[awsl*MAXN],lsh[MAXN],cnt,root[MAXN],f[MAXN][25],dep[MAXN],mdp,o=1,n,m; int read() //o=1 eeeee { reg char c; reg int x=0; //x=0 eeeeeeee c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') { x=x*10+c-48; c=getchar(); } return x; } void add(int u,int v) { r[o].u=u; r[o].v=v; r[o].next=fir[u]; fir[u]=o++; } void dfs(int u,int d) { // printf("u=%d %d ",u,d); dep[u]=d; reg int i,v,j; for(i=fir[u];i;i=r[i].next) { v=r[i].v; if(v==f[u][0]) continue; f[v][0]=u; // printf("%d %d ",u,v); F(j,1,mdp) f[v][j]=f[f[v][j-1]][j-1]; dfs(v,d+1); } } void bfs(int st) { reg int i,j,u,v; dep[st]=1; q.push(st); while(!q.empty()) { u=q.front(); q.pop(); for(i=fir[u];i;i=r[i].next) { v=r[i].v; if(dep[v]) continue; dep[v]=dep[u]+1; f[v][0]=u; F(j,1,mdp) f[v][j]=f[f[v][j-1]][j-1]; q.push(v); } } } int lca(int x,int y) { if(dep[x]>dep[y]) x^=y^=x^=y; // printf("wee%d ",x); reg int i; for(i=mdp;i>=0;--i) if(dep[f[y][i]]>=dep[x]) y=f[y][i]; if(x==y) return x; // if(f[x][0]==f[y][0]) return f[x][0]; for(i=mdp;i>=0;--i) if(f[x][i]!=f[y][i]) { x=f[x][i]; y=f[y][i]; } return f[x][0]; } void up(int k) { // printf("%d %d ",siz[lc[k]],siz[rc[k]]); if(siz[lc[k]]>=siz[rc[k]]) siz[k]=siz[lc[k]],num[k]=num[lc[k]]; else siz[k]=siz[rc[k]],num[k]=num[rc[k]]; } void ch(int &k,int l,int r,int x,int c) { if(!k) k=++tot; if(l==r) { siz[k]+=c; num[k]=l; return; } int mid=(l+r)>>1; if(x<=mid) ch(lc[k],l,mid,x,c); else ch(rc[k],mid+1,r,x,c); up(k); } int merge(int x,int y,int l,int r) { if(!x||!y) return x+y; if(l==r) { siz[x]+=siz[y]; num[x]=l; return x; } int mid=(l+r)>>1; lc[x]=merge(lc[x],lc[y],l,mid); rc[x]=merge(rc[x],rc[y],mid+1,r); // printf("%d %d %d ",siz[x],siz[lc[x]],siz[rc[x]]); up(x); return x; } void dfs2(int u) { reg int i,v; // printf("u=%d ",u); for(i=fir[u];i;i=r[i].next) { v=r[i].v; if(v==f[u][0]) continue; dfs2(v); // printf("root %d ",root[v]); if(root[v]) root[u]=merge(root[u],root[v],1,cnt); } // printf("%d %d ",u,num[root[u]]); ans[u]=siz[root[u]]?lsh[num[root[u]]]:0; } int main() { // freopen("17.in","r",stdin); n=read(); m=read(); mdp=(int)log2(n)+1; reg int i,a,b,c; F(i,1,n-1) { a=read(); b=read(); add(a,b); add(b,a); } dfs(1,1); // dep[0]=-1; // bfs(1); F(i,1,m) ask[i].x=read(),ask[i].y=read(),ask[i].z=lsh[i]=read();//,printf("!!! %d ",ask[i].z); sort(lsh+1,lsh+m+1); cnt=unique(lsh+1,lsh+m+1)-lsh-1; F(i,1,m) ask[i].z=lower_bound(lsh+1,lsh+cnt+1,ask[i].z)-lsh; reg int g; F(i,1,m) { ch(root[ask[i].x],1,cnt,ask[i].z,1); ch(root[ask[i].y],1,cnt,ask[i].z,1); g=lca(ask[i].x,ask[i].y); ch(root[g],1,cnt,ask[i].z,-1); if(f[g][0]) ch(root[f[g][0]],1,cnt,ask[i].z,-1); } dfs2(1); F(i,1,n) printf("%d ",ans[i]); return 0; }