「九省联考 2018」制胡窜 解题报告

「九省联考 2018」制胡窜

苟题目,搞了我一天。

显然要搞一个SAM,然后搞一个线段树合并,关于定位询问串搞一个树上倍增

然后你考虑一个细节贼多的分类讨论

应该是可以不求补集的,我最开始一直这么想但是有个东西不会维护后来发现是可以维护的...

但是补集应该简单一点吧...?

就是每次切两刀要把所有位置的刀切开,这么多细节我肯定懒得说。

说下我错过的(如果你写法和我类似)

注意左边的到切的是[,),右边的切的是(,]

然后就是讨论讨论讨论


Code:

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define ll long long
using std::min;
using std::max;
const int N=2e5+10;
template <class T>
void read(T &x)
{
	x=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
int root[N];
namespace seg
{
	int ch[N*50][2],yuul[N*50],yuur[N*50],tot;
	ll s1[N*50],s2[N*50];
	#define ls ch[now][0]
	#define rs ch[now][1]
	void updata(int now)
	{
		yuul[now]=yuul[ls]?yuul[ls]:yuul[rs];
		yuur[now]=yuur[rs]?yuur[rs]:yuur[ls];
		s1[now]=s1[ls]+s1[rs];
		s2[now]=s2[ls]+s2[rs];
		int r1=yuur[ls],r2=yuul[rs];
		if(r1&&r2)
		{
			s1[now]+=1ll*(r2-r1)*r2;
			s2[now]+=(r2-r1);
		}
	}
	int qryex(int now,int L,int R,int l,int r)//有没有点..
	{
		if(!now) return 0;
		if(l==L&&r==R) return 1;
		int Mid=L+R>>1;
		if(r<=Mid) return qryex(ls,L,Mid,l,r);
		else if(l>Mid) return qryex(rs,Mid+1,R,l,r);
		else return qryex(ls,L,Mid,l,Mid)||qryex(rs,Mid+1,R,Mid+1,r);
	}
	void qrys(int now,int L,int R,int l,int r,ll &ret1,ll &ret2)
	{
	    if(!now) return;
		if(l==L&&r==R)
		{
			ret1+=s1[now],ret2+=s2[now];
			return;
		}
		int Mid=L+R>>1;
		if(r<=Mid) qrys(ls,L,Mid,l,r,ret1,ret2);
		else if(l>Mid) qrys(rs,Mid+1,R,l,r,ret1,ret2);
		else
		{
			qrys(ls,L,Mid,l,Mid,ret1,ret2),qrys(rs,Mid+1,R,Mid+1,r,ret1,ret2);
			int r1=yuur[ls],r2=yuul[rs];
			if(r1&&r2&&r1>=l&&r2<=r)
			{
				ret1+=1ll*(r2-r1)*r2;
				ret2+=(r2-r1);
			}
		}
	}
	//qryri,小于等于某位置最右
	//qryle,大于等于某位置最左
	int qryri(int now,int l,int r,int p)
	{
		if(r==p) return yuur[now];
		int mid=l+r>>1;
		if(p<=mid) return qryri(ls,l,mid,p);
		else return max(yuur[ls],qryri(rs,mid+1,r,p));
	}
	int qryle(int now,int l,int r,int p)
	{
		if(l==p) return yuul[now];
		int mid=l+r>>1;
		if(p<=mid)
		{
			int ret=qryle(ls,l,mid,p);
			if(ret) return ret;
			else return yuul[rs];
		}
		else return qryle(rs,mid+1,r,p);
	}
	void ins(int &now,int l,int r,int p)
	{
		if(!now) now=++tot;
		if(l==r)
		{
			yuul[now]=yuur[now]=l;
			return;
		}
		int mid=l+r>>1;
		if(p<=mid) ins(ls,l,mid,p);
		else ins(rs,mid+1,r,p);
		updata(now);
	}
	int Merge(int x,int y,int l,int r)
	{
		if(!x||!y) return x^y;
		if(l==r) return x;
		int mid=l+r>>1,now=++tot;
		ls=Merge(ch[x][0],ch[y][0],l,mid);
		rs=Merge(ch[x][1],ch[y][1],mid+1,r);
		updata(now);
		return now;
	}
}
ll gets(int n){return 1ll*n*(n+1)/2;}
using seg::ins;
using seg::Merge;
using seg::qryex;
using seg::qryri;
using seg::qryle;
using seg::qrys;
int n,q;
char s[N];
int ch[N][10],len[N],par[N],f[19][N],pos[N],tax[N],A[N],tot=1,las=1;
void extend(int c,int pos)
{
	int now=++tot,p=las;
	ins(root[now],1,n,pos);
	len[now]=len[p]+1;
	while(p&&!ch[p][c]) ch[p][c]=now,p=par[p];
	if(!p) par[now]=1;
	else
	{
		int x=ch[p][c];
		if(len[x]==len[p]+1) par[now]=x;
		else
		{
			int y=++tot;
			len[y]=len[p]+1;
			par[y]=par[x];
			memcpy(ch[y],ch[x],sizeof ch[y]);
			while(p&&ch[p][c]==x) ch[p][c]=y,p=par[p];
			par[now]=par[x]=y;
		}
	}
	las=now;
}
int clim(int now,int d)
{
	for(int i=18;~i;i--)
		if(len[f[i][now]]>=d)
			now=f[i][now];
	return now;
}
//qryri,小于等于某位置最右
//qryle,大于等于某位置最左
ll work(int now,int d)
{
    if(d==1) return 0;
	int lp=qryri(root[now],1,n,n)-d+1;//最右边点的左端点
	int rp=qryle(root[now],1,n,1);//最左边点的右端点
	if(qryex(root[now],1,n,rp+d,lp-1)) return 0;//有3个互不香蕉
	ll ret=0;
	if(rp<=lp)
	{
		int s=qryle(root[now],1,n,lp);//开始的右端点位置
		int t=qryri(root[now],1,n,rp+d-1);//结束的右端点位置
		if(s>t) return (rp-(t-d+1))*(s-lp);
		int nxts=s;//当前的右端点
		s=qryri(root[now],1,n,s-1);//前一个右端点
		if(s) ret+=1ll*(nxts-s)*(nxts-lp);
		ll ret1=0,ret2=0;
		qrys(root[now],1,n,nxts,t,ret1,ret2);
		ret+=ret1-ret2*lp;
		int nxtt=qryle(root[now],1,n,t+1);//后一个右端点
		ret+=1ll*(rp-(t-d+1))*(nxtt-lp);
		return ret;
	}
	ret+=1ll*(rp-d)*(rp-lp);//i不切,j全切
	ret+=1ll*(rp-lp)*(n-1)-(gets(rp-1)-gets(lp-1));
	int s=rp,t=lp+d-1;
	ll ret1=0,ret2=0;
	qrys(root[now],1,n,s,t,ret1,ret2);
	ret+=ret1-ret2*lp;
	//int nxts=qryle(root[now],1,n,s+1);
	//ret+=(nxts-rp)*(nxts-lp+1);
	return ret;
}
int main()
{
	read(n),read(q);
	scanf("%s",s+1);
	for(int i=1;i<=n;i++) extend(s[i]-'0',i),pos[i]=las;
	for(int i=1;i<=tot;i++) ++tax[len[i]];
	for(int i=1;i<=n;i++) tax[i]+=tax[i-1];
	for(int i=1;i<=tot;i++) A[tax[len[i]]--]=i;
	for(int i=tot;i;i--)
	{
		int now=A[i],p=par[now];
		f[0][now]=p;
		root[p]=Merge(root[p],root[now],1,n);
	}
	for(int i=1;i<=tot;i++)
	{
		int now=A[i];
		for(int j=1;f[j-1][now];j++) f[j][now]=f[j-1][f[j-1][now]];
	}
	ll ans=1ll*(n-1)*(n-2)/2;
	for(int l,r,d,i=1;i<=q;i++)
	{
		read(l),read(r),d=r+1-l;
		int now=clim(pos[r],d);
		printf("%lld\n",ans-work(now,d));
	}
	return 0;
}

2019.3.19

posted @ 2019-03-19 22:20  露迭月  阅读(265)  评论(0编辑  收藏  举报