bzoj3946

题解:

树套树

treap+线段树

treap就把线段树上的节点弄一下

然后修改的时候

把中间的一段一起加

把两头重新计算(二分+hash)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned int U;
const int N=600005;
int n,m,x,len,cur,st[N],en[N],q[N][3],stq[N];
int pre[N],y[N],h[N],T[N],tag[N],enq[N];
U po[N];
char op[9],s[N],pool[N],str[N];
namespace DS
{
    const int N=15000005;
    int tot,l[N],r[N],v[N];
    U f[N];
    void up(int x)
     {
         v[x]=v[l[x]]+v[r[x]];
         f[x]=f[l[x]]*po[v[r[x]]]+f[r[x]];
     }
    int build(int a,int b,int c,int d)
     {
        int x=++tot;
        if (a==b)
         {
             v[x]=1;
             f[x]=str[a];
             return x;
         }
        int mid=(a+b)/2;
        if (c<=mid)l[x]=build(a,mid,c,d);
        if (d>mid)r[x]=build(mid+1,b,c,d);
        up(x);
        return x; 
     } 
    int merge(int x,int y,int a,int b)
     {
         if (!x||!y)return x+y;
         int z=++tot,mid=(a+b)/2;
         l[z]=merge(l[x],l[y],a,mid);
         r[z]=merge(r[x],r[y],mid+1,b);
         up(z);
         return z;
     } 
    U hash(int x,int k)
     {
         int a=1,b=cur,mid,t;
         U h=0;
         while (a<b)
          {
              mid=(a+b)/2;
             t=v[l[x]];
             if (k<=t)
              {
                  b=mid;
                  x=l[x];
             }
            else
             {
                 h=h*po[t]+f[l[x]];
                 k-=t;
                 a=mid+1;
                 x=r[x];
             } 
         }
        return h*po[v[x]]+f[x]; 
     } 
}
void ins(int x,int p)
{
    pre[x]=DS::merge(pre[x],p,1,cur);
}
void down(int x)
{
    if (pre[x])
     {
         ins(x<<1,pre[x]);
         ins(x<<1|1,pre[x]);
         pre[x]=0;
     }
}
void push(int x,int a,int b,int c,int d,int p)
{
    if (c<=a&&b<=d)
     {
         ins(x,p);
         return;
     }
    down(x);
    int mid=(a+b)/2;
    if (c<=mid)push(x<<1,a,mid,c,d,p);
    if (d>mid)push(x<<1|1,mid+1,b,c,d,p);
}
void root(int x,int a,int b,int c)
{
    if (a==b)
     {
         T[a]=DS::merge(T[a],pre[x],1,cur);
         pre[x]=0;
         return;
     }
    down(x);
    int mid=(a+b)/2;
    if (c<=mid)root(x<<1,a,mid,c);
    else root(x<<1|1,mid+1,b,c); 
}
int lcp(int x,int y)
{
    root(1,1,n,x);
    root(1,1,n,y);
    x=T[x];y=T[y];
    int l=1,r=min(DS::v[x],DS::v[y]),t=0;
    while (l<=r)
     {
         int mid=(l+r)/2;
         if (DS::hash(x,mid)==DS::hash(y,mid))l=(t=mid)+1;
         else r=mid-1;
     }
    return t; 
}
void tag1(int x,int p)
{
    h[x]+=p;
    tag[x]+=p;
}
void pb(int x)
{
    if (tag[x])
     {
         tag1(x<<1,tag[x]);
         tag1(x<<1|1,tag[x]);
         tag[x]=0;
     }
}
void up(int x)
{
    h[x]=min(h[x<<1],h[x<<1|1]);
}
void build(int x,int a,int b)
{
    if (a==b)
     {
         h[x]=lcp(a,a+1);
         return;
     }
    int mid=(a+b)/2;
    build(x<<1,a,mid);
    build(x<<1|1,mid+1,b);
    up(x); 
}
void cal(int x,int a,int b,int c)
{
    if (a==b)
     {
         h[x]=lcp(a,a+1);
         return;
     }
    pb(x); 
    int mid=(a+b)/2;
    if (c<=mid)cal(x<<1,a,mid,c);
    else cal(x<<1|1,mid+1,b,c); 
    up(x);
}
void change(int x,int a,int b,int c,int d,int p)
{
    if (c<=a&&b<=d)
     {
         tag1(x,p);
         return;
     }
    pb(x);
    int mid=(a+b)/2;
    if (c<=mid)change(x<<1,a,mid,c,d,p);
    if (d>mid)change(x<<1|1,mid+1,b,c,d,p);
    up(x); 
}
int ask(int x,int a,int b,int c,int d)
{
    if (c<=a&&b<=d)return h[x];
    pb(x);
    int mid=(a+b)/2,t=N;
    if (c<=mid)t=ask(x<<1,a,mid,c,d);
    if (d>mid)t=min(t,ask(x<<1|1,mid+1,b,c,d));
    return t;
}
void makepush(int l,int r,int A,int B)
{
    push(1,1,n,l,r,DS::build(1,cur,A,B));
    if (l<r)change(1,1,n-1,l,r-1,B-A+1);
    if (l>1)cal(1,1,n-1,l-1);
    if (r<n)cal(1,1,n-1,r);
}
int query(int l,int r)
{
    if (l==r)return lcp(l,l);
    return ask(1,1,n-1,l,r-1);
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
     {
         scanf("%s",s);
         len=strlen(s);
         st[i]=cur+1;
         for (int j=0;j<len;j++)pool[++cur]=s[j];
         en[i]=cur;
     }
    for (int i=1;i<=m;i++)
     {
         scanf("%s%d%d",op,&q[i][1],&q[i][2]);
         if (op[0]=='Q')q[i][0]=1;
         else
          {
              scanf("%s",s);
              len=strlen(s);
              stq[i]=cur+1;
              for (int j=0;j<len;j++)pool[++cur]=s[j];
              enq[i]=cur;
         }
     } 
    int cur=0;
    for (int i=m;i;i--)
     if (!q[i][0])
      {
          x=cur+1;
          for (int j=stq[i];j<=enq[i];j++)str[++cur]=pool[j];
          stq[i]=x;
          enq[i]=cur;
      } 
    for (int i=1;i<=n;i++)
     {
         x=cur+1;
         for (int j=st[i];j<=en[i];j++)str[++cur]=pool[j];
         st[i]=x;en[i]=cur;
     } 
    po[0]=1; 
    for (int i=1;i<=cur;i++)po[i]=po[i-1]*233;
    for (int i=1;i<=n;i++)T[i]=DS::build(1,cur,st[i],en[i]);
    build(1,1,n-1);
    for (int i=1;i<=m;i++)
     if (q[i][0])printf("%d
",query(q[i][1],q[i][2]));
     else makepush(q[i][1],q[i][2],stq[i],enq[i]); 
}
原文地址:https://www.cnblogs.com/xuanyiming/p/8458134.html