zoukankan      html  css  js  c++  java
  • 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('
    ');}
    
    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
    ",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而已

  • 相关阅读:
    C++如何在Dialog和View中显示梯度背景颜色
    C++MFC的关键类(View,Application,Frame,Document等等)之间访问方法列表
    C++深入分析MFC文档视图结构(项目实践)
    C++如何修改SDI程序的默认背景颜色
    BAPI使用HR_INFOTYPE_OPERATION函数批量导入HR信息纪录代码样例(0759信息类型)
    C++在单文档的应用程序增加多个视图
    SD定价过程的16个字段的作用说明
    HR上载信息类型的长文本的样例代码
    C++在工具条中加入组合框控件
    C++如何锁定splitter窗口
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10543952.html
Copyright © 2011-2022 走看看