[bzoj3946][线段树][哈希]无聊的游戏

39 篇文章 0 订阅
10 篇文章 0 订阅

Description

小K因为学习OI认识了两位神犇,他们分别叫做小H和小Y。两位神犇平时是这么对待小K的: “这不是道傻逼题么” “这都不会做你智商堪忧啊”
“。。。。。。”
小K因此对生活失去了信心。最近两位神犇没什么题刷,于是他们开始用自己做题剩下的史诗级智商来享受生活的快乐——研究游戏开发了。
由于两位神犇太神,不久他们就创造了新的游戏。游戏一开始会给由你N个非空串构成的序列,然后你要进行M次操作。操作分为两种:
第一种操作Insert(L,R,S):表示在[L,R]之间的所有串前都加上一个新的非空串S。
第二种操作Query(L,R):询问[L,R]之间所有串的最长公共前缀。如果L=R,则输出对应串的长度。
两位神犇分分钟就把这个游戏玩通了。于是他们准备虐一虐小K,让他也来玩玩。不出所料,小K被虐得头昏眼花,于是他找到你,看你能不
能帮他一把。小K还需要为NOIP一等奖而奋斗呢。

Input

第1行包含两个正整数N,M。接下来的N行每行都包含一个非空的串S,表示第i个初始的串。再接下来的M行每行的
开头都有一个字母type,type=I'表示这行对应一个Insert操作,而type=Q’时对应一个Query操作。接下来会从
左到右依次给出这个操作的参数。

Output

对于每一个Query操作,输出一行。一行包含一个正整数,表示这组询问的答案。

Sample Input

2 3

noi

noip

Q 1 2

I 2 2 ctsc

Q 1 2

Sample Output

3

0

HINT

令st表示初始时所有串的长度之和, s u m sum sum表示所有 I n s e r t Insert Insert操作中所给串的长度之和。

对于25%的数据,满足N,M<=1000, st,sum<=3000。

对于50%的数据,满足N,M<=20000, st,sum<=40000。

对于100%的数据,满足N,M<=50000,st+sum<=600000

保证所有的串都只包含小写英文字母。

保证有一些数据是随机的。

题解

卡了我半个上午的常数我去
开始在想把他扔到一个Trie上去,然后就是DFS序最小与最大的LCA
然后就发现好像不可维护了…
换个想法
我们用类似后缀数组的思想,如果能维护一个 s u m [ i ] sum[i] sum[i]表示 i i i i − 1 i-1 i1的最长公共前缀
那么 [ l , r ] [l,r] [l,r]的最长公共前缀就是 m i n ( s u m [ l + 1 ] . . . s u m [ r ] ) min(sum[l+1]...sum[r]) min(sum[l+1]...sum[r])
我们来想想怎么维护这个 s u m sum sum
对于一段 [ L , R ] [L,R] [L,R]加,可以直接在 [ L + 1 , R ] [L+1,R] [L+1,R] s u m sum sum上进行区间加
需要单点修改仅有 s u m [ L ] sum[L] sum[L] s u m [ R + 1 ] sum[R+1] sum[R+1]
把询问离线下来,从前往后扫每个串
考虑哈希的思想是 ∑ a i ∗ b a s e k \sum a_i*base^k aibasek
我们可以用线段树维护哈希值,从前一个串到后一个串的操作仅仅是单点修改与区间乘
为了常数可以把线段树可持久化起来…
然后就可以二分找到最长公共前缀
剩余就是简单模拟问题
这居然是我第二个10K代码…

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
#define lc now<<1
#define rc now<<1|1
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(int x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
const int MAXN=50005;
const int MAXM=50005;
const int MAXLEN=600005;
const int mod=1e9+7;
const int base=23;

int pow_mod(int a,int b)
{
	int ret=1;
	while(b)
	{
		if(b&1)ret=1LL*ret*a%mod;
		a=1LL*a*a%mod;b>>=1;
	}
	return ret;
}
inline int _min(int x,int y){return x<y?x:y;}
int mxlen,n,m;
inline int ad(int x,int y){return x+y>mod?x+y-mod:x+y;}
inline void mul(int &x,int y){x=1LL*x*y%mod;}
int mxpos;
struct bittree
{
	int s[MAXLEN];
	bittree(){memset(s,0,sizeof(s));}
	inline int lowbit(int x){return x&-x;}
	inline void modify(int x,int c){for(;x<=mxlen;x+=lowbit(x))s[x]+=c;}
	inline int qry(int x){int ret=0;for(;x>=1;x-=lowbit(x))ret+=s[x];return ret;}
	inline int findKth(int K)
	{
		int now=0,sum=0;
		for(int i=mxpos;i>=0;i--)if(now+(1<<i)<=mxlen&&sum+s[now+(1<<i)]<K)now+=(1<<i),sum+=s[now];
		return now+1;
	}
}bi[2];
int rt[MAXLEN];
int nwpos;
struct segtree1
{
	int sum[MAXLEN*35],tag[MAXLEN*35],lson[MAXLEN*35],rson[MAXLEN*35],tot;
	int newnode(int u)
	{
		tot++;
		sum[tot]=sum[u];tag[tot]=tag[u];
		lson[tot]=lson[u];rson[tot]=rson[u];
		return tot;
	}
	void buildtree(int &now,int l,int r)
	{
		now=++tot;
		sum[now]=0;tag[now]=1;
		if(l==r)return ;
		int mid=(l+r)/2;
		buildtree(lson[now],l,mid);buildtree(rson[now],mid+1,r);
	}
	void down(int now)
	{
		if(tag[now]==1)return ;
		lson[now]=newnode(lson[now]);rson[now]=newnode(rson[now]);
		mul(sum[lson[now]],tag[now]);mul(sum[rson[now]],tag[now]);
		mul(tag[lson[now]],tag[now]);mul(tag[rson[now]],tag[now]);
		tag[now]=1;
	}
	void md1(int &now,int l,int r,int ql,int qr,int mu)
	{
		if(ql>qr)return ;
		if(now<nwpos)now=newnode(now);
		if(l==ql&&r==qr){mul(sum[now],mu);mul(tag[now],mu);return ;}
		int mid=(l+r)/2;down(now);
		if(qr<=mid)md1(lson[now],l,mid,ql,qr,mu);
		else if(mid+1<=ql)md1(rson[now],mid+1,r,ql,qr,mu);
		else md1(lson[now],l,mid,ql,mid,mu),md1(rson[now],mid+1,r,mid+1,qr,mu);
		sum[now]=ad(sum[lson[now]],sum[rson[now]]);
	}
	void md2(int &now,int l,int r,int p,int c)
	{
		if(now<nwpos)now=newnode(now);
		if(l==r){sum[now]=c;return ;}
		int mid=(l+r)/2;down(now);
		if(p<=mid)md2(lson[now],l,mid,p,c);
		else md2(rson[now],mid+1,r,p,c);
		sum[now]=ad(sum[lson[now]],sum[rson[now]]);
	}
	int qry(int now,int l,int r,int ql,int qr)
	{
		if(l==ql&&r==qr)return sum[now];
		int mid=(l+r)/2;down(now);
		if(qr<=mid)return qry(lson[now],l,mid,ql,qr);
		else if(mid+1<=ql)return qry(rson[now],mid+1,r,ql,qr);
		else return ad(qry(lson[now],l,mid,ql,mid),qry(rson[now],mid+1,r,mid+1,qr));
	}
}seg1;
struct segtree2
{
	int id[MAXN*4],tag[MAXN*4];
	void down(int now)
	{
		if(!tag[now])return ;
		id[lc]=id[rc]=tag[lc]=tag[rc]=tag[now];
		tag[now]=0;
	}
	void buildtree(int now,int l,int r)
	{
		if(l==r){id[now]=l;return ;}
		int mid=(l+r)/2;
		buildtree(lc,l,mid);buildtree(rc,mid+1,r);
	}
	void modify(int now,int l,int r,int ql,int qr,int c)
	{
		if(l==ql&&r==qr){id[now]=tag[now]=c;return ;}
		int mid=(l+r)/2;down(now);
		if(qr<=mid)modify(lc,l,mid,ql,qr,c);
		else if(mid+1<=ql)modify(rc,mid+1,r,ql,qr,c);
		else modify(lc,l,mid,ql,mid,c),modify(rc,mid+1,r,mid+1,qr,c);
	}
	int qry(int now,int l,int r,int p)
	{
		if(l==r)return id[now];
		int mid=(l+r)/2;down(now);
		if(p<=mid)return qry(lc,l,mid,p);
		else return qry(rc,mid+1,r,p);
	}
}seg2;
struct segtree3
{
	int mn[MAXN*4],tag[MAXN*4];
	void down(int now)
	{
		if(!tag[now])return ;
		mn[lc]+=tag[now];mn[rc]+=tag[now];
		tag[lc]+=tag[now];tag[rc]+=tag[now];
		tag[now]=0;
	}
	void md1(int now,int l,int r,int ql,int qr,int c)
	{
		if(l==ql&&r==qr){mn[now]+=c;tag[now]+=c;return ;}
		int mid=(l+r)/2;down(now);
		if(qr<=mid)md1(lc,l,mid,ql,qr,c);
		else if(mid+1<=ql)md1(rc,mid+1,r,ql,qr,c);
		else md1(lc,l,mid,ql,mid,c),md1(rc,mid+1,r,mid+1,qr,c);
		mn[now]=_min(mn[lc],mn[rc]);
	}
	void md2(int now,int l,int r,int p,int c)
	{
		if(l==r){mn[now]=c;return ;}
		int mid=(l+r)/2;down(now);
		if(p<=mid)md2(lc,l,mid,p,c);
		else md2(rc,mid+1,r,p,c);
		mn[now]=_min(mn[lc],mn[rc]);
	}
	int qry(int now,int l,int r,int ql,int qr)
	{
		if(l==ql&&r==qr){return mn[now];}
		int mid=(l+r)/2;down(now);
		if(qr<=mid)return qry(lc,l,mid,ql,qr);
		else if(mid+1<=ql)return qry(rc,mid+1,r,ql,qr);
		else return min(qry(lc,l,mid,ql,mid),qry(rc,mid+1,r,mid+1,qr));
	}
}seg3;
char ma[MAXLEN];
char ch[MAXLEN],ss[10];
int ls[2*MAXN],rs[2*MAXN];
int answer[MAXN];
struct oper
{
	int l,r,o,id;
	oper(){}
	oper(int _l,int _r,int _o,int _id){l=_l;r=_r;o=_o;id=_id;}
}w[4*MAXN];int ln1;//0 求和操作  1 修改操作  2 加操作 
struct ask
{
	int u,id1,id2,pos;
	ask(){}
	ask(int _u,int _id1,int _id2,int _pos){u=_u;id1=_id1;id2=_id2;pos=_pos;}
}w1[4*MAXN];int ln2;
//struct node
//{
//	int u,first,second;
//	node(){}
//	node(int _u,int _first,int _second){u=_u;first=_first;second=_second;}
//};w2[4*MAXN];int ln3;

struct node
{
	int first,second;
	node(){}
	node(int _first,int _second){first=_first;second=_second;}
};
bool cmp(ask n1,ask n2){return n1.u<n2.u;}
//bool cmp1(node n1,node n2){return n1.u<n2.u;}
vector<node> vec2[MAXN];

int inv;
int po[2];
void getnxt(int o,int u)
{
//	for(;w2[po[o]].u==u&&po[o]<=ln3;++po[o])
	if(o==0)
	{
		rt[u]=rt[u-1];nwpos=seg1.tot+1;
		for(register int j=0;j<(int)vec2[u].size();++j)
		{
			int id=vec2[u][j].first,op=vec2[u][j].second;
			if(op==-1)seg1.md1(rt[u],1,mxlen,ls[id],rs[id],0),seg1.md1(rt[u],1,mxlen,1,ls[id]-1,pow_mod(inv,rs[id]-ls[id]+1));
			else seg1.md1(rt[u],1,mxlen,1,ls[id]-1,pow_mod(base,rs[id]-ls[id]+1));
			int total=bi[o].qry(mxlen)-bi[o].qry(ls[id]);
			for(register int k=ls[id];k<=rs[id];++k)
			{
				int x=ma[k]-'a'+1;
				if(op==-1)bi[o].modify(k,-1);
				else
				{
					int lst=total+(rs[id]-k+1);
					seg1.md2(rt[u],1,mxlen,k,1LL*x*pow_mod(base,lst)%mod);
					bi[o].modify(k,1);
				}
			}
		}
	}
	else
	{
		for(register int j=0;j<vec2[u].size();++j)
		{
			int id=vec2[u][j].first,op=vec2[u][j].second;
			int total=bi[o].qry(mxlen)-bi[o].qry(ls[id]);
			for(register int k=ls[id];k<=rs[id];++k)
			{
				int u=ma[k]-'a'+1;
				if(op==-1)bi[o].modify(k,-1);
				else bi[o].modify(k,1);
			}
		}
	}
}
bool check(int i,int u1,int u2,int ln)
{
	int u=bi[0].qry(u1),lst1=bi[0].findKth(u+ln-1),p1=bi[0].qry(mxlen)-u+1;
	int v=bi[1].qry(u2),lst2=bi[1].findKth(v+ln-1),p2=bi[1].qry(mxlen)-v+1;
	int s1=seg1.qry(rt[i],1,mxlen,u1,lst1),s2=seg1.qry(rt[i-1],1,mxlen,u2,lst2);
	if(p1<p2)s1=1LL*s1*pow_mod(base,p2-p1)%mod;
	else s2=1LL*s2*pow_mod(base,p1-p2)%mod;
	return s1==s2;
}
int main()
{
//	freopen("3946.in","r",stdin);
//	freopen("3946.out","w",stdout);
	inv=pow_mod(base,mod-2);
	n=read();m=read();
	int ln=0;seg2.buildtree(1,1,n);
	for(register int i=1;i<=n;++i)
	{
		scanf("%s",ch+1);int len=strlen(ch+1);
		ls[i]=ln+1;rs[i]=ln+len;mxlen+=len;
		for(register int j=1;j<=len;++j)ma[++ln]=ch[len-j+1];
//		w2[++ln3]=node(i,i,1);w2[++ln3]=node(i+1,i,-1);
		vec2[i].push_back(node(i,1));vec2[i+1].push_back(node(i,-1));
		if(i-1)
		{
			w[++ln1]=oper(i,0,1,0);
			w1[++ln2]=ask(i,i,i-1,ln1);
//			vec1[i].push_back(ask(i,i-1,ln1));
		}
	}
	int total=0,up=n;
	for(register int i=1;i<=m;++i)
	{
		scanf("%s",ss+1);
		int l=read(),r=read();
		if(ss[1]=='Q')
		{
			if(l==r)answer[++total]=rs[l]-ls[l]+1+bi[0].qry(l);
			else
			{
				ln1++;
				w[ln1].l=l;w[ln1].r=r;w[ln1].o=0;w[ln1].id=++total;//求和操作 
			}
		}
		else
		{
			scanf("%s",ch+1);int len=strlen(ch+1);
			up++;mxlen+=len;
			bi[0].modify(l,len);bi[0].modify(r+1,-len);
			ls[up]=ln+1;rs[up]=ln+len;
			for(int j=1;j<=len;j++)ma[++ln]=ch[len-j+1];
//			w2[++ln3]=node(l,up,1);w2[++ln3]=node(r+1,up,-1);
			vec2[l].push_back(node(up,1));vec2[r+1].push_back(node(up,-1));
			seg2.modify(1,1,n,l,r,up);
			if(l-1)
			{
				int u=seg2.qry(1,1,n,l),v=seg2.qry(1,1,n,l-1);
//				vec1[l].push_back(ask(u,v,++ln1));
				w1[++ln2]=ask(l,u,v,++ln1);
//				if(u==1235&&v==1241)printf("YES %d %d\n",l,r);
				w[ln1]=oper(l,0,1,0);
			}
			if(r+1<=n)
			{
				int u=seg2.qry(1,1,n,r+1),v=seg2.qry(1,1,n,r);
//				if(u==1235&&v==1241)printf("NO %d %d\n",l,r);
//				vec1[r+1].push_back(ask(u,v,++ln1));
				w1[++ln2]=ask(r+1,u,v,++ln1);
				w[ln1]=oper(r+1,0,1,0);
			}
			if(l+1<=r)w[++ln1]=oper(l+1,r,2,len);
		}
	}
	for(;(1<<mxpos)<mxlen;mxpos++);
	sort(w1+1,w1+1+ln2,cmp);
//	sort(w2+1,w2+1+ln3,cmp1);
	po[0]=po[1]=1;
	memset(bi[0].s,0,sizeof(bi[0].s));
	for(register int i=1;i<=up;++i)ls[i]=ln-ls[i]+1,rs[i]=ln-rs[i]+1,swap(ls[i],rs[i]);
	reverse(ma+1,ma+1+ln);
	
	seg1.buildtree(rt[0],1,mxlen);
//	seg1[1].buildtree(1,1,mxlen);
	getnxt(0,1);
	getnxt(0,2);
	getnxt(1,1);
//	printf("%d\n",seg1[0].qry(1,1,mxlen,5,6));
	int LST=1;
	for(register int i=2;i<=n;++i)
	{
		if(w1[LST].u==i)
		{
			for(register int j=LST;w1[j].u==i&&j<=ln2;++j)
			{
				LST=j;
				int u1=ls[w1[j].id1],u2=ls[w1[j].id2],pos=w1[j].pos;
				
				int d1=seg1.qry(rt[i],1,mxlen,u1,u1),d2=seg1.qry(rt[i-1],1,mxlen,u2,u2);
				int p1=bi[0].qry(mxlen)-bi[0].qry(u1)+1,p2=bi[1].qry(mxlen)-bi[1].qry(u2)+1;
				if(p1<p2)d1=1LL*d1*pow_mod(base,p2-p1)%mod;
				else d2=1LL*d2*pow_mod(base,p1-p2)%mod;
				if(d1!=d2)continue;
				
				int l1=bi[0].qry(mxlen)-bi[0].qry(u1-1);
				int l2=bi[1].qry(mxlen)-bi[1].qry(u2-1);
				
				
				int l=1,r=min(l1,l2),as=0;
				while(l<=r)
				{
					int mid=(l+r)/2;
					if(check(i,u1,u2,mid))as=mid,l=mid+1;
					else r=mid-1;
				}
				w[pos].id=as;
			}
			LST++;
		}
		if(i+1<=n)getnxt(0,i+1);
		getnxt(1,i);
	}
	for(register int i=1;i<=ln1;++i)
	{
		if(!w[i].o)answer[w[i].id]=seg3.qry(1,1,n,w[i].l+1,w[i].r);
		else if(w[i].o==1)seg3.md2(1,1,n,w[i].l,w[i].id);
		else seg3.md1(1,1,n,w[i].l,w[i].r,w[i].id);
	}
	for(int i=1;i<=total;i++)pr2(answer[i]);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值