zoukankan      html  css  js  c++  java
  • 【LOJ 6041】「雅礼集训 2017 Day7」事情的相似度

    Description

    人的一生不仅要靠自我奋斗,还要考虑到历史的行程。

    历史的行程可以抽象成一个 01 串,作为一个年纪比较大的人,你希望从历史的行程中获得一些姿势。

    你发现在历史的不同时刻,不断的有相同的事情发生。比如,有两个人同时在世纪之交 11 年的时候上台,同样喜欢与洋人谈笑风生,同样提出了以「三」字开头的理论。

    你发现,一件事情可以看成是这个 01 串的一个前缀,这个前缀最右边的位置就是这个事情的结束时间。

    两件事情的相似度可以看成,这两个前缀的最长公共后缀长度。

    现在你很好奇,在一段区间内结束的事情中最相似的两件事情的相似度是多少呢?

    Input

    第一行两个整数 n、m,表示串长和询问个数。
    第二行长度为 n 的 01 串,表示历史的行程。
    接下来 m 行,每行两个正整数 l r 表示询问的区间,包括端点,保证1≤l<r≤n

    Output

    输出 m 行,对每个询问输出一个整数表示最大的相似度。

     

    建出原串的SAM,则两个前缀的最长公共后缀为他们在parent树上的lca,问题转化为求区间内前缀两两lca深度的最大值。

    将询问离线,按右端点从小到大排序。我们考虑每次加入一个字母,就将他们在parent树上到根节点的路径打上他们的标记。往根节点跑的过程中,若遇到了以前打的标记,则该节点为旧标记与新标记的lca。贪心可得应把标记尽量覆盖为较大的值。用树状数组来统计答案,下标为左端点,每次查询下标大于等于该询问左端点的最大深度。向根跑的过程中每一次遇到旧标记,就在树状数组上更新答案,并给该节点打上新标记。

    往根节点跑的过程实际上就是LCT的access。

      1 #include<cstdio>
      2 #include<algorithm> 
      3 #include<cstring>
      4 #include<vector>
      5 #define LL long long
      6 using namespace std;
      7 const int N=1e5+5;
      8 int n,m,r,last,size,root;
      9 int p[N],mx[N],ans[N],num[N];
     10 int c[N*2][2],fa[N*2],v[N*2],tag[N*2];
     11 char s[N];
     12 vector<int> q[N];
     13 struct sam{int mx,fa,ch[2];}t[N*2];
     14 int read()
     15 {
     16     int x=0,f=1;char c=getchar();
     17     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
     18     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
     19     return x*f;
     20 }
     21 int lowbit(int x){return x&(-x);}
     22 void modify(int x,int v){x=n-x+1;while(x<=n)mx[x]=max(mx[x],v),x+=lowbit(x);}
     23 int query(int x){x=n-x+1;int ans=0;while(x)ans=max(ans,mx[x]),x-=lowbit(x);return ans;}
     24 void ins(int c,int id)
     25 {
     26     int np=++size;num[id]=np;
     27     t[np].mx=t[last].mx+1;
     28     int x=last;last=np;
     29     while(x&&!t[x].ch[c])t[x].ch[c]=np,x=t[x].fa;
     30     if(!x)t[np].fa=root;
     31     else
     32     {
     33         int y=t[x].ch[c];
     34         if(t[y].mx==t[x].mx+1)t[np].fa=y;
     35         else
     36         {
     37             int nq=++size;
     38             t[nq]=t[y];t[nq].mx=t[x].mx+1;
     39             t[y].fa=t[np].fa=nq;
     40             while(x&&t[x].ch[c]==y)t[x].ch[c]=nq,x=t[x].fa;
     41         }
     42     }
     43 }
     44 bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
     45 void change(int x,int val){v[x]=tag[x]=val;}
     46 void down(int x)
     47 {
     48     if(!tag[x])return;
     49     if(c[x][0])change(c[x][0],tag[x]);
     50     if(c[x][1])change(c[x][1],tag[x]);
     51     tag[x]=0;
     52 }
     53 void rotate(int x)
     54 {
     55     int y=fa[x],z=fa[y],l,r;
     56     if(c[y][0]==x)l=0;else l=1;r=l^1;
     57     if(!isroot(y)){if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;}
     58     fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
     59     c[y][l]=c[x][r];c[x][r]=y;
     60 }
     61 void relax(int x){if(!isroot(x))relax(fa[x]);down(x);}
     62 void splay(int x)
     63 {
     64     relax(x);
     65     while(!isroot(x))
     66     {
     67         int y=fa[x],z=fa[y];
     68         if(!isroot(y))
     69         {
     70             if((c[y][0]==x)^(c[z][0]==y))rotate(x);
     71             else rotate(y);
     72         }
     73         rotate(x);
     74     }
     75 }
     76 void access(int x,int val)
     77 {
     78     int o=0;
     79     while(x)
     80     {
     81         splay(x);modify(v[x],t[x].mx);
     82         c[x][1]=o;o=x;x=fa[x];
     83     }
     84     tag[o]=v[o]=val;
     85 }
     86 void build(){for(int i=1;i<=size;i++)fa[i]=t[i].fa;}
     87 int main()
     88 {
     89     n=read();m=read();
     90     scanf("%s",s+1);
     91     for(int i=1;i<=m;i++)
     92     {
     93         p[i]=read();r=read();
     94         q[r].push_back(i);
     95     }
     96     last=size=root=1;
     97     for(int i=1;i<=n;i++)ins(s[i]-'0',i);
     98     build();
     99     for(int i=1;i<=n;i++)
    100     {
    101         access(num[i],i);
    102         int sz=q[i].size();
    103         for(int j=0;j<sz;j++)
    104         {
    105             int x=q[i][j];
    106             ans[x]=query(p[x]);
    107         }
    108     }
    109     for(int i=1;i<=m;i++)printf("%d
    ",ans[i]);
    110     return 0;
    111 }
    View Code
  • 相关阅读:
    [POJ 1050]To the Max
    P1678 烦恼的高考志愿
    P1873 砍树
    P1102 A-B 数对
    P6771 [USACO05MAR]Space Elevator 太空电梯
    P2347 砝码称重
    P1832 A+B Problem(再升级)
    P1679 神奇的四次方数
    P1877 [HAOI2012]音量调节
    P1049 装箱问题
  • 原文地址:https://www.cnblogs.com/zsnuo/p/8899302.html
Copyright © 2011-2022 走看看