zoukankan      html  css  js  c++  java
  • 「九省联考 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
    ",ans-work(now,d));
    	}
    	return 0;
    }
    

    2019.3.19

  • 相关阅读:
    百度云管家开机启动如何取消
    双语小说阅读:《谁动了我的奶酪》
    [Swift]方法
    Swift中的类型属性(静态变量)
    Swift 学习之二十一:?和 !(详解)
    苹果Swift可为Windows/Android开发软件了
    iOS7下滑动返回与ScrollView共存二三事
    swift c++ oc 混编
    RTOS
    STM32 RTC
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10561892.html
Copyright © 2011-2022 走看看