• [BZOJ2555]SubString


    SAM+LCT模板题。
    题目相当于求询问串在SAM上走到的状态的right集合大小,等于parent树上这个节点的子树中有多少前缀节点(right集合大小为1的节点)。
    因为强制在线,所以parent树用LCT维护。注意是维护子树和。代码还是非常好写的,也非常好想。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 601000;
    
    char str[N];
    void getstr(int p){
    	scanf("%s",str);
    	int len = strlen(str);
    	for (int i = 0;i < len;i++){
    		p = (p*131+i)%len;
    		swap(str[i],str[p]);
    	}
    }
    
    struct Node{
    	int son[2],fa,sum,sum1,sum2;
    	Node(){}
    	Node(int _fa,int _sum):fa(_fa),sum(_sum),sum1(_sum){
    		son[0] = son[1] = sum2 = 0;}
    };
    struct Lct{
    	Node nod[N<<1];
    	void insert(int p,int d){
    		nod[p] = Node(0,d);
    	}
    	void link(int x,int y){
    		access(x);
    		access(y);
    		splay(x);
    		splay(y);
    		nod[x].fa = y;
    		nod[y].sum2 += nod[x].sum;
    		nod[y].sum += nod[x].sum;
    	}
    	void cut(int x){
    		access(x);
    		splay(x);
    		int u = nod[x].son[0];
    		if (u){
    			nod[x].son[0] = 0;
    			update(x);
    			nod[u].fa = 0;
    		}
    	}
    	void access(int x){
    		int y = 0;
    		while (x){
    			splay(x);
    			//!!!!
    			int u = nod[x].son[1];
    			if (u) nod[x].sum2 += nod[u].sum;
    			if (nod[y].fa == x) nod[x].sum2 -= nod[y].sum;
    			nod[x].son[1] = y;
    			update(x);
    			y = x;x = nod[x].fa;
    		}
    	}
    	void splay(int x){
    		int w;
    		while ((w = check(x)) != -1){
    			int y = nod[x].fa;
    			if (w == check(y)) rotate(y,w^1);
    			rotate(x,w^1);
    		}
    	}
    	void rotate(int x,int d){
    		int y = nod[x].fa,z = nod[y].fa,w = check(y);
    		nod[x].fa = z;
    		if (w != -1) nod[z].son[w] = x;
    		nod[y].son[d^1] = nod[x].son[d];
    		if (nod[x].son[d]) nod[nod[x].son[d]].fa = y;
    		nod[y].fa = x;
    		nod[x].son[d] = y;
    		update(y);
    		update(x);
    	}
    	void update(int p){
    		int u = nod[p].son[0],v = nod[p].son[1];
    		nod[p].sum = nod[p].sum1+nod[p].sum2;
    		if (u) nod[p].sum += nod[u].sum;
    		if (v) nod[p].sum += nod[v].sum;
    	}
    	int check(int x){
    		int y = nod[x].fa;
    		if (!y) return -1;
    		if (nod[y].son[0] == x) return 0;
    		if (nod[y].son[1] == x) return 1;
    		return -1;
    	}
    	int getans(int p){
    		if (p == 0) return 0;
    		access(p);
    		splay(p);
    		return nod[p].sum-nod[nod[p].son[0]].sum;
    	}
    }lct;
    
    struct State{
    	int go[26],par,val;
    	State(){}
    	State(int _val):par(0),val(_val){
    		memset(go,0,sizeof(go));
    	}
    }state[N<<1];
    int root = 1,len = 1,last = 1;
    
    int q,mask,lastans;
    char opt[10];
    void extend(int);
    int trans();
    int main(){
    	scanf("%d",&q);
    	scanf("%s",str);
    	int slen = strlen(str);
    	for (int i = 0;i < slen;i++) 
    		extend(str[i]-'A');
    	while (q--){
    		scanf("%s",opt);
    		if (opt[0] == 'A'){
    			getstr(mask);
    			int lenn = strlen(str);
    			for (int i = 0;i < lenn;i++) 
    				extend(str[i]-'A');
    		}
    		else{
    			getstr(mask);
    			lastans = 0;
    			int u = trans();
    			lastans = lct.getans(u);
    			printf("%d
    ",lastans);
    			mask ^= lastans;
    		}
    	}
    	return 0;
    }
    void extend(int w){
    	int p = last,np = ++len;
    	state[np] = State(state[p].val+1);		
    	lct.insert(np,1);
    	while (p && state[p].go[w] == 0) 
    		state[p].go[w] = np,p = state[p].par;
    	if (p == 0){
    		state[np].par = root;
    		lct.link(np,root);
    	}
    	else{
    		int q = state[p].go[w];
    		if (state[q].val == state[p].val+1){
    			state[np].par = q;
    			lct.link(np,q);
    		}
    		else{
    			int nq = ++len;state[nq] = State(state[p].val+1);
    			lct.insert(nq,0);
    			memcpy(state[nq].go,state[q].go,sizeof(state[q].go));
    			state[nq].par = state[q].par;
    			state[q].par = nq;
    			state[np].par = nq;
    			lct.cut(q);
    			lct.link(nq,state[nq].par);
    			lct.link(q,nq);
    			lct.link(np,nq);
    			while (p && state[p].go[w] == q)
    				state[p].go[w] = nq,p = state[p].par;
    		}
    	}
    	last = np;
    }
    int trans(){
    	int len = strlen(str);
    	int p = root;
    	for (int i = 0;i < len;i++)
    		p = state[p].go[str[i]-'A'];
    	return p;
    }
    
  • 相关阅读:
    windows的80端口被占用时的处理方法
    Ansible自动化运维工具安装与使用实例
    Tomcat的测试网页换成自己项目首页
    LeetCode 219. Contains Duplicate II
    LeetCode Contest 177
    LeetCode 217. Contains Duplicate
    LeetCode 216. Combination Sum III(DFS)
    LeetCode 215. Kth Largest Element in an Array(排序)
    Contest 176 LeetCode 1354. Construct Target Array With Multiple Sums(优先队列,递推)
    Contest 176
  • 原文地址:https://www.cnblogs.com/victbr/p/6774740.html
Copyright © 2020-2023  润新知