zoukankan      html  css  js  c++  java
  • [JSOI2008]火星人prefix

    题意

    维护一个由小写字母构成的字符串,要求支持单点修改,插入单个字符,查询两个后缀的(LCP)

    思路

    LCP是可以用二分+hash检验的,支持插入操作自然可以想到平衡树,由于hash可以使用线段树或者平衡树维护,所以本题平衡树+二分即可

    本题需要一定卡常

    Code

    #include<bits/stdc++.h>
    #define N 400005
    using namespace std;
    typedef unsigned int ULL;
    const ULL tp = 1000000007;
    int n,m,root;
    char a[N];
    ULL po[N];
    
    struct T
    {
    	int size,ch[2],key;
    	ULL val,sum;
    }t[N];
    int cnt;
    
    template <class T>
    void read(T &x)
    {
    	char c;int sign=1;
    	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    	while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;
    }
    inline void update(int x)
    {
    	t[x].size=t[t[x].ch[0]].size+t[t[x].ch[1]].size+1;
    	t[x].sum=t[t[x].ch[1]].sum + t[x].val*po[t[t[x].ch[1]].size] + t[t[x].ch[0]].sum*po[t[t[x].ch[1]].size+1];
    }
    inline int add_node(int x)
    {
    	++cnt;
    	t[cnt].ch[0]=t[cnt].ch[1]=0;
    	t[cnt].key=rand(); t[cnt].size=1;
    	t[cnt].sum=t[cnt].val=x;
    	return cnt;
    }
    int merge(int l,int r)
    {
    	if(!l||!r) return l+r;
    	if(t[l].key<t[r].key)
    	{
    		t[l].ch[1]=merge(t[l].ch[1],r);
    		update(l);
    		return l;
    	}
    	else
    	{
    		t[r].ch[0]=merge(l,t[r].ch[0]);
    		update(r);
    		return r;
    	}
    }
    void split(int rt,int x,int &l,int &r)
    {
    	if(!rt) {l=r=0;return;}
    	if(t[t[rt].ch[0]].size+1<=x) {l=rt;split(t[rt].ch[1],x-t[t[rt].ch[0]].size-1,t[rt].ch[1],r);}
    	else {r=rt;split(t[rt].ch[0],x,l,t[rt].ch[0]);}
    	update(rt);
    }
    inline void add(int pos,int x)//在pos后面加一个元素 
    {
    	int l,r;
    	split(root,pos,l,r);
    	root=merge(merge(l,add_node(x)),r);
    }
    inline void del(int pos)
    {
    	int l,r,p;
    	split(root,pos-1,l,r);
    	split(r,1,p,r);
    	root=merge(l,r);
    }
    inline ULL ask(int x,int y)//询问hash(x,y)
    {
    	int l,r,p;
    	split(root,x-1,l,r);
    	split(r,y-x+1,p,r);
    	ULL ret=t[p].sum;
    	root=merge(l,merge(p,r));
    	return ret;
    }
    inline int query(int x,int y)//询问LCP(x,y) 
    {
    	if(x>y) swap(x,y);
    	int l=1,r=n-y+1,ans=0;
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(ask(x,x+mid-1)==ask(y,y+mid-1)) l=mid+1,ans=mid;
    		else r=mid-1;
    	}
    	return ans;
    }
    int main()
    {
    	srand((unsigned)time(NULL));srand(rand());
    	po[0]=1;
    	for(int i=1;i<=200000;++i) po[i]=po[i-1]*tp; 
    	
    	scanf("%s",a);
    	n=strlen(a);
    	for(int i=1;i<=n;++i) add(i-1,a[i-1]-'a'+1);//建树 
    	
    	read(m);
    	while(m--)
    	{
    		char op[2];
    		scanf("%s",op);
    		if(op[0]=='Q')//询问 
    		{
    			int x,y; read(x); read(y);
    			printf("%d
    ",query(x,y));
    		}
    		else if(op[0]=='R')//修改 
    		{
    			int x; read(x); scanf("%s",op);
    			del(x);
    			add(x-1,op[0]-'a'+1);
    		}
    		else//插入 
    		{
    			++n;
    			int x; read(x); scanf("%s",op);
    			add(x,op[0]-'a'+1);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Luogu P2391 白雪皑皑 && BZOJ 2054: 疯狂的馒头 并查集
    Luogu P3391 文艺平衡树(Splay or FHQ Treap)
    [笔记] 平衡树合集(Treap,Splay,替罪羊,FHQ Treap)
    P1353_[USACO08JAN]跑步Running 我死了。。。
    Luogu P1436 棋盘分割 暴力DP
    Luogu P1131 [ZJOI2007]时态同步 树形DP
    Luogu P1282 多米诺骨牌 DP。。背包?
    Luogu P1273 有线电视网 树形DP
    Luogu P1272 重建道路 树形DP
    Luogu P1156 垃圾陷阱 DP
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11426130.html
Copyright © 2011-2022 走看看