bzoj3946: 无聊的游戏
并不是一道很无聊的题2333
Description
给定n个串,支持:
1.区间在最前面压入一个串
2.区间求LCP
n<=50000,sum<=600000
Solution
区间压串,,??
先考虑区间求LCP,相邻LCP最小值!
故维护区间height最小值mh
区间压串?
对于[l+1,r]mh都加上len
l,r+1要hei不知道怎么变
必须重新找LCP
必须知道原串具体情况
LCP还要修改,hash+二分!
考虑,
给整个区间打上一个串的标记。。。
下放?直接复制gg
标记永久化?有先后,不能合并!
还是下放?不能直接复制?可持久化!
可持久化线段树?merge复杂度感觉不太对,且空间太大
可持久化平衡树?可持久化平衡树!
fhq-treap可持久化一下,外层二分mid
内层找hash值:
wrk0,wrk1在边界时候特殊讨论
代码:
(借鉴yjc代码和细节提醒少了很多弯路,,,一遍AC)
#include<bits/stdc++.h> #define reg register int #define il inline #define fi first #define se second #define mk(a,b) make_pair(a,b) #define numb (ch^'0') #define uint unsigned int #define mid ((l+r)>>1) using namespace std; typedef long long ll; template<class T>il void rd(T &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');} template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');} template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');} namespace Miracle{ const int N=50000+5; const int M=600000+5; const int inf=0x3f3f3f3f; const uint base=131; int n,m; uint mi[M]; struct treap{ int ls,rs; int sz; uint hsh; uint v; int pri; }t[18000000+5]; int tpc; int nc(char v){ ++tpc;t[tpc].hsh=t[tpc].v=v;t[tpc].pri=rand();t[tpc].sz=1;return tpc; } int sta[M],top; void up(int x){ if(!x) return; t[x].sz=t[t[x].ls].sz+t[t[x].rs].sz+1; t[x].hsh=t[t[x].ls].hsh+(t[x].v+base*t[t[x].rs].hsh)*mi[t[t[x].ls].sz]; } void dfs(int x){ if(!x) return; // cout<<x<<" "<<t[x].ls<<" "<<t[x].rs<<endl; dfs(t[x].ls);dfs(t[x].rs); up(x); } int cons(){ int ret=0; top=0; char c; while(!isalpha(c=getchar())); for(;isalpha(c);c=getchar()){ int now=nc(c); // cout<<" now "<<now<<" ls "<<t[now].ls<<" rs "<<t[now].rs<<" c "<<c<<endl; int las=0; while(top&&t[sta[top]].pri>t[now].pri) las=sta[top],--top; if(sta[top]) t[sta[top]].rs=now; sta[++top]=now; t[now].ls=las; // cout<<" las "<<las<<endl; } ret=sta[1]; // cout<<" ret "<<ret<<endl; dfs(ret); // cout<<" after dfs "<<endl; return ret; } int merge(int x,int y){ if(!x||!y) return x|y; int now; if(t[x].pri<t[y].pri){ now=nc(t[x].v); t[now].ls=t[x].ls; t[now].rs=merge(t[x].rs,y); }else{ now=nc(t[y].v); t[now].rs=t[y].rs; t[now].ls=merge(x,t[y].ls); } up(now);return now; } uint calc(int x,int k){ if(!x||!k) return 0; if(t[t[x].ls].sz>=k) return calc(t[x].ls,k); else{ return t[t[x].ls].hsh+(t[x].v+base*calc(t[x].rs,k-t[t[x].ls].sz-1))*mi[t[t[x].ls].sz]; } } int lcp(int x,int y){//x y is treap's rt // cout<<" lcp "<<x<<" "<<y<<endl; int l=0,r=min(t[x].sz,t[y].sz); int ret=0; while(l<=r){ // cout<<"erfen "<<l<<" "<<r<<" : "<<mid<<endl; if(calc(x,mid)==calc(y,mid)) ret=mid,l=mid+1; else r=mid-1; } return ret; } #define oooooooooooooooooooooooooooooooooooooooooooooo segmenttree int rt[2*N]; int ls[2*N],rs[2*N]; int mh[2*N],tag[2*N]; int seg[N]; int sgc; void pushup(int x){ mh[x]=min(mh[ls[x]],mh[rs[x]]); } void pushdown(int x,int l,int r){ if(l==r) return; if(tag[x]){ mh[ls[x]]+=tag[x]; tag[ls[x]]+=tag[x]; mh[rs[x]]+=tag[x]; tag[rs[x]]+=tag[x]; tag[x]=0; } if(rt[x]){ rt[ls[x]]=merge(rt[x],rt[ls[x]]); rt[rs[x]]=merge(rt[x],rt[rs[x]]); rt[x]=0; } } void pd(int x){ if(tag[x]){ mh[ls[x]]+=tag[x]; tag[ls[x]]+=tag[x]; mh[rs[x]]+=tag[x]; tag[rs[x]]+=tag[x]; tag[x]=0; } } void build(int x,int l,int r){ // cout<<" build "<<x<<" "<<l<<" "<<r<<endl; if(l==r){ rt[x]=seg[l]; // cout<<" rt[x] "<<rt[x]<<" "<<seg[l]<<endl; mh[x]=lcp(seg[l-1],seg[l]); // cout<<" mh[x] "<<mh[x]<<endl; return; } ls[x]=++sgc;rs[x]=++sgc; build(ls[x],l,mid);build(rs[x],mid+1,r); pushup(x); } int getrt(int x,int l,int r,int p){ if(l==r){ return rt[x]; } pushdown(x,l,r); if(p<=mid) return getrt(ls[x],l,mid,p); else return getrt(rs[x],mid+1,r,p); } void fhq(int x,int l,int r,int L,int R,int nrt){ pushdown(x,l,r); if(L<=l&&r<=R){ rt[x]=merge(nrt,rt[x]);return; } if(L<=mid) fhq(ls[x],l,mid,L,R,nrt); if(mid<R) fhq(rs[x],mid+1,r,L,R,nrt); } void add(int x,int l,int r,int L,int R,int c){//nrt is treap if(L<=l&&r<=R){ mh[x]+=c;tag[x]+=c;return; } pd(x); if(L<=mid) add(ls[x],l,mid,L,R,c); if(mid<R) add(rs[x],mid+1,r,L,R,c); pushup(x); } void chan(int x,int l,int r,int p,int c){//single point if(l==r){ mh[x]=c;return; } pd(x); if(p<=mid) chan(ls[x],l,mid,p,c); else chan(rs[x],mid+1,r,p,c); pushup(x); } int qmin(int x,int l,int r,int L,int R){ if(L<=l&&r<=R){ return mh[x]; } pd(x); int ret=inf; if(L<=mid) ret=min(ret,qmin(ls[x],l,mid,L,R)); if(mid<R) ret=min(ret,qmin(rs[x],mid+1,r,L,R)); return ret; } void wrk0(int l,int r){//ins int nrt=cons(); fhq(1,1,n,l,r,nrt); if(l+1<=r) add(1,1,n,l+1,r,t[nrt].sz); if(l!=1){ int rt1=getrt(1,1,n,l); int rt2=getrt(1,1,n,l-1); int len=lcp(rt1,rt2); chan(1,1,n,l,len); } if(r!=n){ int rt1=getrt(1,1,n,r); int rt2=getrt(1,1,n,r+1); int len=lcp(rt1,rt2); chan(1,1,n,r+1,len); } } int wrk1(int l,int r){//query if(l==r){ int lp=getrt(1,1,n,l); return t[lp].sz; }else{ return qmin(1,1,n,l+1,r); } } int main(){ srand(19260817); rd(n);rd(m); mi[0]=1; for(reg i=1;i<=M-4;++i) mi[i]=mi[i-1]*base; for(reg i=1;i<=n;++i){ seg[i]=cons(); } ++sgc; // cout<<"00000000000 "<<t[0].sz<<endl; build(1,1,n); char op[233]; int l,r; while(m--){ scanf("%s",op+1);rd(l);rd(r); if(op[1]=='Q'){ printf("%d\n",wrk1(l,r)); }else{ wrk0(l,r); } } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/3/16 17:03:13 */
区间标记还能这么打?
单个标记直接打
树套树标记永久化
但是可以有时可以用可持久化数据结构当做标记!时间空间多了一个logn而已