• BZOJ4545: DQS的trie


    BZOJ4545: DQS的trie

    https://lydsy.com/JudgeOnline/problem.php?id=4545

    分析:

    • 对trie用dfs建sam复杂度是(O(n^2))的,因为你不能让一个复杂度带均摊的东西去一直回溯。
    • 构造数据卡也很好卡,一条链边全是a,每个点连出去一条不是a的边。
    • 于是我们用bfs建sam,这样复杂度是对的?
    • 说这道题的做法,第一个询问每次插入时动态维护即可,第二问操作我们用lct维护后缀链接树。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 400050
    #define isrt(p) (ch[f[p]][1]!=p&&ch[f[p]][0]!=p)
    typedef long long ll;
    int ch[N][3],fa[N],len[N],cnt=1,pos[N],n;
    ll nowans;
    int head[N],to[N],nxt[N],CNT,val[N];
    inline void add(int u,int v,int w) {
    	to[++CNT]=v; nxt[CNT]=head[u]; head[u]=CNT; val[CNT]=w;
    }
    int tr[N];
    struct LCT {
    	#define ls ch[p][0]
    	#define rs ch[p][1]
    	#define get(x) (ch[f[x]][1]==x)
    	int ch[N][2],tag[N],f[N];
    	void rotate(int x) {
    		int y=f[x],z=f[y],k=get(x);
    		if(!isrt(y)) ch[z][ch[z][1]==y]=x;
    		ch[y][k]=ch[x][!k]; f[ch[y][k]]=y;
    		ch[x][!k]=y; f[y]=x; f[x]=z; 
    	}
    	inline void giv(int p,int d) {
    		tag[p]+=d; tr[p]+=d;
    	}
    	inline void pushdown(int p) {
    		if(tag[p]) {
    			if(ls) giv(ls,tag[p]);
    			if(rs) giv(rs,tag[p]);
    			tag[p]=0;
    		}
    	}
    	void UPD(int p) {
    		if(!isrt(p)) UPD(f[p]);
    		pushdown(p);
    	}
    	void splay(int x) {
    		UPD(x);
    		for(int d;d=f[x],!isrt(x);rotate(x)) {
    			if(!isrt(d)) rotate(get(x)==get(d)?d:x);
    		}
    	}
    	void access(int p) {
    		int t=0;
    		while(p) {
    			splay(p); rs=t; t=p; p=f[p];
    		}
    	}
    	void cut(int p) {
    		access(p); splay(p); f[ls]=0; ls=0;
    	}
    	void link(int p,int q) {
    		f[p]=q;
    	}
    }_;
    int insert(int x,int lst) {
    	int p=lst,np,q,nq;
    	np=++cnt; lst=np;
    	len[np]=len[p]+1;
    	for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
    	if(!p) fa[np]=1,nowans+=len[np],_.link(np,1);
    	else {
    		q=ch[p][x];
    		if(len[q]==len[p]+1) fa[np]=q,nowans+=len[np]-(len[fa[np]]),_.link(np,q);
    		else {
    			nq=++cnt;
    			len[nq]=len[p]+1;
    			memcpy(ch[nq],ch[q],sizeof(ch[q]));
    			_.UPD(q); tr[nq]=tr[q];
    			nowans-=(len[q]-len[fa[q]]);
    			fa[nq]=fa[q]; 
    			_.link(nq,fa[q]); 
    
    			fa[q]=fa[np]=nq;
    			_.cut(q); _.link(q,nq); _.link(np,nq);
    			nowans+=(len[q]-len[fa[q]])+(len[nq]-len[fa[nq]])+(len[np]-len[fa[np]]);
    
    			for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
    		}
    	}
    	_.access(lst), _.splay(lst), _.giv(lst,1);
    	return lst;
    }
    int Q[N];
    bool vis[N];
    void bfs(int x) {
    	int i,l=0,r=0;
    	Q[r++]=x; vis[x]=1;
    	while(l<r) {
    		x=Q[l++];
    		for(i=head[x];i;i=nxt[i]) if(!vis[to[i]]) {
    			vis[to[i]]=1; pos[to[i]]=insert(val[i],pos[x]); Q[r++]=to[i];
    		}
    	}
    }
    char w[N];
    int main() {
    	scanf("%*d%d",&n);
    	int i,x,y;
    	pos[1]=1;
    	char oo[10];
    	for(i=1;i<n;i++) {
    		scanf("%d%d%s",&x,&y,oo+1);
    		add(x,y,oo[1]-'a'),add(y,x,oo[1]-'a');
    	}
    	bfs(1);
    	int m;
    	scanf("%d",&m);
    	int sz;
    	while(m--) {
    		int opt;
    		scanf("%d",&opt);
    		if(opt==1) {
    			printf("%lld
    ",nowans);
    		}else if(opt==2) {
    			int rt;
    			scanf("%d%d",&rt,&sz); head[rt]=0;
    			for(i=1;i<sz;i++) {
    				scanf("%d%d%s",&x,&y,oo+1);
    				add(x,y,oo[1]-'a'), add(y,x,oo[1]-'a');
    			}
    			bfs(rt);
    		}else {
    			scanf("%s",w+1);
    			int k=strlen(w+1),p=1;
    			for(i=1;i<=k;i++) {
    				x=w[i]-'a';
    				if(ch[p][x]) p=ch[p][x];
    				else {p=ch[p][x]; break;}
    			}
    			if(!p) {puts("0");continue ;}
    			_.splay(p); 
    			printf("%d
    ",tr[p]);
    		}
    	}
    }
    
  • 相关阅读:
    Cousera课程Learning How to Learn学习报告
    C语言中当无符号数遇到符号数
    STC15 串口(工作方式1)使用小结
    取C语言头文件的文件名
    linux 的 shell 逻辑
    Win7 局域网内简单共享的设置
    写了一个批处理,可以实现文件备份,自动对比删除冗余文件。
    C语言 函数指针的应用
    自动控制原理 典型环节频率特性对比
    51单片机汇编的溢出标志位OV和进位标志位CY
  • 原文地址:https://www.cnblogs.com/suika/p/10051245.html
Copyright © 2020-2023  润新知