bzoj3946: 无聊的游戏

并不是一道很无聊的题2333

Description

给定n个串,支持:

1.区间在最前面压入一个串

2.区间求LCP

n<=50000,sum<=600000

Solution

 %%yjc

区间压串,,??

先考虑区间求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而已

 

posted @ 2019-03-16 19:34  *Miracle*  阅读(263)  评论(2编辑  收藏  举报