【平衡树】CC_TASUFFIX Very Long Suffix Array

版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/89260467

【题目】
CC

给定一个长度为 n n s a sa 数组,有两种操作:

  • 翻转一段区间
  • 将一段区间移动到开头
    求有多少个本质不同的字符串符合最后得到的 s a sa ,字符串本质不同的意思是不存在一种方式重标号(相同字符标号一样)后两个字符串相同。
    n 1 0 9 , m 1 0 5 n\leq 10^9,m\leq 10^5

【解题思路】
第一眼, n n 怎么这么大,神题吧。
第二眼,还要动态维护操作,神题吧。
还有 s a i sa_i 表示的是排名为 i i 的字符串是第 s a i sa_i 个这玩意坑了我挺久来着。

茫茫久后,发现只需要最后输出答案。而答案实际上就是若 s a i sa_i s a i + 1 sa_{i+1} 的位置两个字符可以相同则有 2 2 的乘积贡献。
也就是说,若 s a i < s a i + 1 sa_i<sa_{i+1} ,则 r k s a i + 1 < r k s a i + 1 + 1 rk_{{sa_i}+1}<rk_{sa_{i+1}+1} 有贡献,这个可以用个 map \text{map} 什么的实现判断,反正巨麻烦。

一段 s a sa 连续的序列答案很容易求,因此我们只需要考虑不连续的位置。
由于 n n 很大,但 m m 比较小,还要支持翻转和移动,我们考虑用平衡树维护这个东西。
维护方式显然就是初始一个点代表一个区间,每次操作最多将两个区间拆分,平衡树上每个点维护一下代表的区间和是否翻转之类的就可以了。
最后可用一个一个节点考虑答案,平衡树使用 splay \text{splay} fhqtreap \text{fhqtreap} 这类可提出区间的即可。
复杂度 O ( n log n ) O(n\log n) ,细节还是很多的(心累)。

最后吐槽一下,数据太水了,我一个本该完全错的代码竟然能过。
所以大家写这个题目就算交过了,但最好多拿几个代码对拍一下吧。

【参考代码】

#include<bits/stdc++.h>
using namespace std;

const int N=4e5+10,mod=1e9+7;

int read()
{
	int ret=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return ret;
}

namespace Data_Structure
{
	int rt,nowl,nowr;
	struct Splay
	{
		#define ls ch[x][0]
		#define rs ch[x][1]
		int sz;
		int L[N],R[N],rev[N],fa[N],siz[N],ch[N][2];
		int glen(int x){return abs(R[x]-L[x])+1;}
		void rever(int x){swap(L[x],R[x]);rev[x]^=1;}
		void pushup(int x){siz[x]=siz[ls]+siz[rs]+glen(x);}
		void pushdown(int x){if(rev[x]) swap(ls,rs),rever(ls),rever(rs),rev[x]=0;}
		int get(int x){return ch[fa[x]][1]==x;}
		void rotate(int x)
		{
			int y=fa[x],z=fa[y],k=get(x);
			if(z) ch[z][get(y)]=x;
			fa[ch[x][!k]]=y;fa[y]=x;fa[x]=z;
			ch[y][k]=ch[x][!k];ch[x][!k]=y;
			pushup(y);pushup(x);
		}
		void splay(int x,int goal)
		{
			while(fa[x]!=goal)
			{
				int y=fa[x];
				if(fa[y]!=goal) rotate(get(y)==get(x)?y:x);
				rotate(x);
			}
			if(!goal) rt=x;
		}
		int findx(int k)
		{
			int x=rt,t=0;
			while(1)
			{
				pushdown(x);
				nowl=t+siz[ls]+1;nowr=nowl+glen(x)-1;
				if(k<=siz[ls]) x=ls;
				else if(k>siz[ls]+glen(x)) k-=siz[ls]+glen(x),t+=siz[ls]+glen(x),x=rs;
				else break;
			}
			--nowl;--nowr;
			return x;
		}
		int divr(int x,int k)
		{
			if(k==nowl) return x;
			int p=++sz;
			if(L[x]<=R[x])
			{
				L[p]=R[x]-(nowr-k);R[p]=R[x];
				R[x]=L[p]-1;
			}
			else 
			{
				L[p]=R[x]+(nowr-k);R[p]=R[x];
				R[x]=L[p]+1;
			}
			ch[p][1]=rs;rs=0;
			fa[p]=fa[x];fa[x]=p;ch[p][0]=x;
			ch[fa[p]][ch[fa[p]][1]==x]=p;
			if(ch[p][1]) fa[ch[p][1]]=p;
			pushup(x);pushup(p);
			if(rt==x) rt=p;
			return p;
		}
		int divl(int x,int k)
		{
			if(k==nowr) return x;
			int p=++sz;
			if(L[x]<=R[x])
			{
				R[p]=L[x]+(k-nowl);L[p]=L[x];
				L[x]=R[p]+1;
			}
			else 
			{
				R[p]=L[x]-(k-nowl);L[p]=L[x];
				L[x]=R[p]-1;
			}
			ch[p][0]=ls;ls=0;
			fa[p]=fa[x];fa[x]=p;ch[p][1]=x;
			ch[fa[p]][ch[fa[p]][1]==x]=p;
			if(ch[p][0]) fa[ch[p][0]]=p;
			pushup(x);pushup(p);
			if(rt==x) rt=p;
			return p;
		}
		void solve(int l,int r)
		{
			int x=findx(l);x=divl(x,l-1);
			int y=findx(r+2);y=divr(y,r+1);
			splay(x,0);splay(y,x);
		}
		void add(int l,int r,int f,int d)
		{
			int x=++sz;
			L[x]=l;R[x]=r;fa[x]=f;
			ch[f][d]=x;siz[x]=r-l+1;
			pushup(x);pushup(f);
		}
		#undef ls
		#undef rs
	}T;
}
using namespace Data_Structure;

namespace DreamLolita
{
	int n,Q,cnt;
	int L[N],R[N];
	map<int,int>mp;
	struct data
	{
		int l,r,L,R;
	}a[N];
	bool cmpl(const data&a,const data&b){return a.l<b.l;}
	bool cmpL(const data&a,const data&b){return a.L<b.L;}
	int gnex(int k,int x,int op)
	{
		if(x==n) return 0;
		return mp[x+1]?mp[x+1]:k+op;
	}
	int qpow(int x,int y){int res=1;for(;y;y>>=1,x=1ll*x*x%mod)if(y&1)res=1ll*res*x%mod;return res;}
	void dfs(int x)
	{
		if(!x) return; T.pushdown(x);
		dfs(T.ch[x][0]);L[++cnt]=T.L[x];R[cnt]=T.R[x];dfs(T.ch[x][1]);
	}
	void solution()
	{
		n=read();Q=read();
		rt=T.sz=1;
		T.add(n+1,n+1,1,1);T.add(1,n,2,0);
		while(Q--)
		{
			int op=read(),l=read(),r=read();
			if(op&1) T.solve(l,r),T.rever(T.ch[T.ch[rt][1]][0]);
			else
			{
				if(l^1)
				{
					T.solve(l,r);
					int x=T.ch[T.ch[rt][1]][0],y=T.ch[rt][1];
					T.pushdown(y);T.fa[x]=0;T.ch[y][0]=0;T.pushup(y);
					T.solve(1,1);y=T.ch[T.ch[rt][1]][0];
					T.pushdown(y);T.ch[y][0]=x;T.fa[x]=y;T.pushup(y);
				}
			}
		}
		cnt=-1;dfs(rt);
		int now=0,ans=0;
		for(int i=1;i<cnt;++i)
		{
			//printf("%d %d\n",L[i],R[i]);
			++now;int l=now,r=now+abs(R[i]-L[i]);now+=abs(R[i]-L[i]);
			if(L[i]>R[i]) swap(L[i],R[i]),swap(l,r);
			a[i].l=l;a[i].r=r;a[i].L=L[i];a[i].R=R[i];
		}
		sort(a+1,a+cnt,cmpL);a[cnt].l=0;
		for(int i=1;i<cnt;++i)
		{
			ans+=max(abs(a[i].r-a[i].l)-1,0);
			if(abs(a[i].r-a[i].l)>=1)
			{
				if(a[i].l<a[i].r) ans+=(a[i+1].l>a[i].r);
				if(a[i].l>a[i].r) ans+=(a[i+1].l<a[i].r);
			}
		}
		for(int i=1;i<cnt;++i) mp[a[i].L]=a[i].l,mp[a[i].R]=a[i].r;
		sort(a+1,a+cnt,cmpl);
		for(int i=1;i<cnt-1;++i)
		{
			if(a[i].l<=a[i].r)
			{
				if(a[i+1].l<=a[i+1].r) ans+=(gnex(a[i+1].l,a[i+1].L,1)>mp[a[i].R+1]);
				else ans+=(mp[a[i+1].R+1]>mp[a[i].R+1]);
			}
			else
			{
				if(a[i+1].l<=a[i+1].r) ans+=(gnex(a[i+1].l,a[i+1].L,1)>gnex(a[i].l,a[i].L,-1));
				else ans+=(mp[a[i+1].R+1]>gnex(a[i].l,a[i].L,-1));
			}
		}
		printf("%d\n",qpow(2,ans));
	}
}

int main()
{
#ifdef Durant_Lee
	freopen("CC_TASUFFIX.in","r",stdin);
	freopen("CC_TASUFFIX.out","w",stdout);
#endif
	DreamLolita::solution();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Dream_Lolita/article/details/89260467