zoukankan      html  css  js  c++  java
  • 【洛谷 P4384】 [八省联考2018]制胡窜(SAM / 线段树合并)

    传送门

    首先建出SamSam,线段树合并维护endposendpos
    显然考虑endposendpos问题可以变成

    给定xx条线段[li,ri][l_i,r_i]
    选择两个点切下去,存在某条线段未被切开的方案

    首先转化成求所有线段都被切开的方案
    C(n1)2C^2_{(n-1)}减去即可
    L=r1,R=lxL=r_1,R=l_x

    然后分几种情况考虑:
    1、存在线段Lli,riRLle l_i,r_ile R
    那此时答案一定为0

    2、L>RL>R
    那么此时考虑两种情况
    (1):要么两个点分别切开一些线段
    (2):要么一个点切开所有线段,另一个点随便放
    (1):
    考虑一个放在[li,li+1)[l_i,l_{i+1})内,那另一个必须在[R,ri+1)[R,r_{i+1})
    那么这个的方案就是
    i(li+1li)(ri+1R)sum_{i}(l_{i+1}-l_i)(r_{i+1}-R)
    =i(ri+1ri)(ri+1R)=sum_{i}(r_{i+1}-r_i)(r_{i+1}-R)
    (2):
    注意不要与(1)中的重了
    所以此时的方案为(LR2)+(LR)(nlen){L-Rchoose 2}+(L-R)(n-len)

    3、即LRLle R,且所有其他线段与线段11xx相连
    仍然考虑类似2(1)的做法
    那么可以得到方案为i(ri+1ri)(ri+1R)sum_i(r_{i+1}-r_i)(r_{i+1}-R)
    注意此时需要满足Rri+1,li+1LRle r_{i+1},l_{i+1}le L

    考虑还有就是最后一个合法区间[lp+1,L),[l_{p+1},L),
    pre,sufpre,suf分别为L+len1L+len-1的前面和后面第一个rr
    那么贡献就还有(sufR)(Lper+len1)(suf-R)(L-per+len-1)

    用线段树合并的时候维护一下mn,mx,i(ri+1ri),iri+1(ri+1ri)mn,mx,sum_{i}(r_{i+1}-r_i),sum_{i}r_{i+1}(r_{i+1}-r_i)

    具体实现可以看代码

    #include<bits/stdc++.h>
    using namespace std;
    #define cs const
    #define re register
    #define pb push_back
    #define pii pair<int,int>
    #define ll long long
    #define fi first
    #define se second
    #define bg begin
    cs int RLEN=1<<20|1;
    inline char gc(){
        static char ibuf[RLEN],*ib,*ob;
        (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
        return (ib==ob)?EOF:*ib++;
    }
    inline int read(){
        char ch=gc();
        int res=0;bool f=1;
        while(!isdigit(ch))f^=ch=='-',ch=gc();
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
        return f?res:-res;
    }
    inline void readstring(char *s){
    	int top=0;char ch=gc();
    	while(isspace(ch))ch=gc();
    	while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
    }
    template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
    template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
    cs int N=100005;
    int n,q;
    namespace Seg{
    	cs int N=::N*70;
    	int mn[N],mx[N],tot,lc[N],rc[N],last;
    	ll s1[N],s2[N],tp1,tp2;
    	#define mid ((l+r)>>1)
    	inline int copy(int r1){
    		int u=++tot;mn[u]=mn[r1],mx[u]=mx[r1],lc[u]=lc[r1],rc[u]=rc[r1],s1[u]=s1[r1],s2[u]=s2[r1];
    		return u;
    	}
    	inline void pushup(int u){
    		if(!lc[u])mn[u]=mn[rc[u]],mx[u]=mx[rc[u]];
    		else if(!rc[u])mn[u]=mn[lc[u]],mx[u]=mx[lc[u]];
    		else mn[u]=mn[lc[u]],mx[u]=mx[rc[u]];
    		s1[u]=s1[lc[u]]+s1[rc[u]],s2[u]=s2[lc[u]]+s2[rc[u]];
    		if(!lc[u]||!rc[u])return;
    		int del=mn[rc[u]]-mx[lc[u]];
    		s1[u]+=del*mn[rc[u]],s2[u]+=del;
    	}
    	void insert(int &u,int l,int r,int p){
    		u=copy(u);if(l==r){mx[u]=mn[u]=p;return;}
    		if(p<=mid)insert(lc[u],l,mid,p);else insert(rc[u],mid+1,r,p);
    		pushup(u);
    	}
    	void merge(int &u,int v){
    		if(!u&&!v)return;
    		if(!u||!v){u=copy(u+v);return;}
    		u=copy(u);
    		merge(lc[u],lc[v]),merge(rc[u],rc[v]);
    		pushup(u);
    	}
    	int querymn(int u,int l,int r,int st,int des){
    		if(!u||st>des)return 1e9;
    		if(st<=l&&r<=des)return mn[u];
    		int ret=1e9;
    		if(st<=mid)chemn(ret,querymn(lc[u],l,mid,st,des));
    		if(ret<1e9)return ret;
    		if(mid<des)chemn(ret,querymn(rc[u],mid+1,r,st,des));
    		return ret;
    	}
    	int querymx(int u,int l,int r,int st,int des){
    		if(!u||st>des)return -1e9;
    		if(st<=l&&r<=des)return mx[u];
    		int ret=-1e9;
    		if(mid<des)chemx(ret,querymx(rc[u],mid+1,r,st,des));
    		if(ret>-1e9)return ret;
    		if(st<=mid)chemx(ret,querymx(lc[u],l,mid,st,des));
    		return ret;
    	}
    	void query(int u,int l,int r,int st,int des){
    		if(!u)return;
    		if(st<=l&&r<=des){
    			int del=mn[u]-last;last=mx[u];
    			tp1+=s1[u]+1ll*del*mn[u];
    			tp2+=s2[u]+del;
    			return;
    		}
    		if(st<=mid)query(lc[u],l,mid,st,des);
    		if(mid<des)query(rc[u],mid+1,r,st,des);
    	}
    	inline int ask(int u,int l,int r,int fir,int k){
    		last=fir,tp1=tp2=0,query(u,1,n,l,r);
    		return tp1-tp2*k;
    	}
    	inline int calc(int u,int k){
    		return s1[u]-s2[u]*k;
    	}
    	#undef mid
    }
    inline ll C2(int x){return 1ll*x*(x-1)/2;}
    namespace Sam{
    	cs int N=::N<<1;
    	int f[18][N],last=1,tot=1;
    	int fa[N],nxt[N][10],len[N],pos[N],ps[N];
    	inline void insert(int c,int id){
    		int cur=++tot,p=last;last=cur;
    		len[cur]=len[p]+1,pos[id]=cur,ps[cur]=id;
    		for(;p&&!nxt[p][c];p=fa[p])nxt[p][c]=cur;
    		if(!p)fa[cur]=1;
    		else{
    			int q=nxt[p][c];
    			if(len[p]+1==len[q])fa[cur]=q;
    			else{
    				int clo=++tot;
    				fa[clo]=fa[q],len[clo]=len[p]+1;
    				memcpy(nxt[clo],nxt[q],sizeof(nxt[q]));
    				for(;p&&nxt[p][c]==q;p=fa[p])nxt[p][c]=clo;
    				fa[cur]=fa[q]=clo;
    			}
    		}
    	}
    	int buc[N],rk[N],rt[N];
    	inline void build(){
    		for(int i=1;i<=tot;i++)buc[len[i]]++,f[0][i]=fa[i];
    		for(int i=1;i<=tot;i++)buc[i]+=buc[i-1];
    		for(int i=1;i<=tot;i++)rk[buc[len[i]]--]=i;
    		for(int i=1;i<=17;i++)
    		for(int j=1;j<=tot;j++)f[i][j]=f[i-1][f[i-1][j]];
    		for(int i=tot;i>=1;i--){
    			int u=rk[i];
    			if(ps[u])Seg::insert(rt[u],1,n,ps[u]);
    			Seg::merge(rt[fa[u]],rt[u]);
    		}
    	}
    	inline int jump(int u,int k){
    		for(int i=17;~i;i--){
    			if(len[f[i][u]]>=k)u=f[i][u];
    		}
    		return u;
    	}
    	inline ll query(int l,int r){
    		int u=pos[r],len=r-l+1;u=jump(u,len);
    		int L=Seg::mn[rt[u]],R=Seg::mx[rt[u]]-len+1;
    		if(R<=L)return C2(n-1)-(Seg::calc(rt[u],R)+C2(L-R)+1ll*(L-R)*(n-len));
    		int pre=Seg::querymx(rt[u],1,n,1,R),suf;
    		if(pre-len+1>=L)return C2(n-1);
    		ll res=Seg::ask(rt[u],R+1,L+len-1,pre,R);
    		pre=Seg::querymx(rt[u],1,n,1,L+len-1),suf=Seg::querymn(rt[u],1,n,L+len,n);
    		if(pre!=1e9&&suf!=-1e9&&suf>R)res+=1ll*(suf-R)*(L-pre+len-1);
    		return C2(n-1)-res;
    	}
    }
    char s[N];
    int main(){
    	#ifdef Stargazer
    	freopen("lx.in","r",stdin);
    	#endif
    	n=read(),q=read();
    	readstring(s);
    	for(int i=1;i<=n;i++)Sam::insert(s[i]-'0',i);
    	Sam::build();
    	while(q--){
    		int l=read(),r=read();
    		cout<<Sam::query(l,r)<<'
    ';
    	}
    	return 0;
    }
    
  • 相关阅读:
    iOS中点击按钮复制指定内容
    iOS开发中,获取图片之后保存或下载到本地相册中
    This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSPhotoLibraryAddUsageDescription key with a string value
    ios中友盟集成好使用总结
    ios中仿蚂蚁森林动画效果
    window frida安装
    Android_server提示端口被占用
    Android stdio Apktool源码编译
    Android ooVoo Apk附件关联分析
    cocos2d-x-2.2.6 project-creator文件夹下python.bat
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328297.html
Copyright © 2011-2022 走看看