zoukankan      html  css  js  c++  java
  • Luogu3732 [HAOI2017] 供给侧改革 【后缀数组】【线段树】【乱搞】

    题目分析:

    这道题我是乱搞的,因为他说$01$串是随机的。

    那么我们可以猜测能够让LCP变大的地方很少。求出后缀数组之后可能让LCP变大的地方就等价于从大到小往height里动态加点同时维护这个点左右两边的单调栈。

    这个事情用线段树模拟就行了。

    用暴力跑一下发现果然不大,只有200w,其中很多还是废点,把废点特判一下删除掉就行了。

    然后把询问离线,按r排序,再作扫描线,每次扫到r的时候把前面变动的LCP更新一下。然后对于询问也做一个类似上面单调栈的操作。

    代码:

      1 #include<bits/stdc++.h>
      2 #define RI register
      3 using namespace std;
      4 
      5 const int maxn = 100020;
      6 const int N = 100000;
      7 
      8 int n,q;
      9 char str[maxn];
     10 int T[maxn<<2],a[maxn];
     11 int RMQ[maxn][19],pw[maxn];
     12 
     13 struct node{int l,r,nb;}qy[maxn];
     14 int ans[maxn];
     15 int sa[maxn],rk[maxn],X[maxn],Y[maxn];
     16 int ht[maxn],h[maxn];
     17 
     18 void fstread(int &x){
     19     char ch = getchar();x = 0;
     20     while(ch > '9' || ch < '0') ch = getchar();
     21     while(ch >= '0' && ch <= '9') x = x*10+ch-'0',ch=getchar();
     22 }
     23 
     24 int chk(int x,int k){
     25     return rk[sa[x]]==rk[sa[x-1]]&&rk[sa[x]+(1<<k)]==rk[sa[x-1]+(1<<k)];
     26 }
     27 
     28 void GetSA(){
     29     for(RI int i=0;i<n;i++) X[str[i]]++;
     30     for(RI int i=1;i<=N;i++) X[i] += X[i-1];
     31     for(RI int i=n-1;i>=0;i--) sa[X[str[i]]--] = i;
     32     for(RI int i = 2, num = 1;i <= n;i++)
     33     rk[sa[i]] = (str[sa[i]] == str[sa[i-1]]?num:++num);
     34     rk[sa[1]] = 1;
     35     for(int k=1;(1<<k-1)<=n;k++){
     36     for(RI int i=1;i<=N;i++) X[i] = 0;
     37     for(RI int i=n-(1<<k-1);i<n;i++) Y[i-n+(1<<k-1)+1]=i;
     38     for(RI int i=1,j=(1<<k-1)+1;i<=n;i++)
     39         if(sa[i]>=(1<<k-1))Y[j++]=sa[i]-(1<<k-1);
     40     for(RI int i=0;i<n;i++) X[rk[i]]++;
     41     for(RI int i=1;i<=N;i++) X[i]+=X[i-1];
     42     for(RI int i=n;i>=1;i--) sa[X[rk[Y[i]]]--] = Y[i];
     43     int num = 1; Y[sa[1]] = 1;
     44     for(RI int i=2;i<=n;i++) Y[sa[i]] = (chk(i,k-1)?num:++num);
     45     for(RI int i=0;i<n;i++) rk[i] = Y[i];
     46     if(num == n) break;
     47     }
     48 }
     49 
     50 void buildRMQ(){
     51     for(int i=1;i<=n;i++) RMQ[i][0] = ht[i];
     52     for(int i=0;(1<<i)<=n;i++) pw[(1<<i)] = i;
     53     for(int i=3;i<=n;i++) if(!pw[i]) pw[i] = pw[i-1];
     54     for(int k=1;(1<<k)<=n;k++){
     55     for(RI int i=1;i<=n;i++){
     56         if(i+(1<<k-1)>n) RMQ[i][k] = RMQ[i][k-1];
     57         else RMQ[i][k] = min(RMQ[i][k-1],RMQ[i+(1<<k-1)][k-1]);
     58     }
     59     }
     60 }
     61 
     62 void GetHeight(){
     63     for(RI int i=0;i<n;i++){
     64     if(i) h[i] = max(0,h[i-1]-1);
     65     if(rk[i] == 1) {h[i] = 0;continue;}
     66     while(str[i+h[i]] == str[sa[rk[i]-1]+h[i]]) h[i]++;
     67     }
     68     for(RI int i=0;i<n;i++) ht[rk[i]] = h[i];
     69 }
     70 
     71 int LCP(int l,int r){
     72     l = rk[l],r = rk[r]; if(l > r) swap(l,r);l++;
     73     int k = pw[r-l+1];
     74     return min(RMQ[l][k],RMQ[r-(1<<k)+1][k]);
     75 }
     76 
     77 void update(int now,int tl,int tr,int pos,int len){
     78     if(tl == tr){T[now] = max(T[now],len); return;}
     79     int mid = (tl+tr)/2;
     80     if(pos <= mid) update(now<<1,tl,mid,pos,len);
     81     else update(now<<1|1,mid+1,tr,pos,len);
     82     T[now] = max(T[now<<1],T[now<<1|1]);
     83 }
     84 
     85 int Query(int now,int tl,int tr,int l,int r,int mx){
     86     if(tl >= l && tr <= r){
     87     if(T[now] <= mx) return -1;
     88     else{
     89         while(tl < tr){
     90         int mid = (tl+tr)/2;
     91         if(T[now<<1|1] > mx) tl = mid+1,now = now*2+1;
     92         else tr = mid,now<<=1;
     93         }
     94         return tl;
     95     }
     96     }
     97     if(tl > r || tr < l) return -1;
     98     int mid = (tl+tr)/2;
     99     if(mid >= r) return Query(now<<1,tl,mid,l,r,mx);
    100     if(mid < l) return Query(now<<1|1,mid+1,tr,l,r,mx);
    101     int z = Query(now<<1|1,mid+1,tr,l,r,mx);
    102     if(z!=-1) return z;
    103     else return Query(now<<1,tl,mid,l,r,mx);
    104 }
    105 
    106 vector<int> mlgb[maxn];
    107 
    108 namespace BruteForce{
    109     int minn[maxn<<2];
    110     
    111     pair<int,int> QueryRange(int now,int tl,int tr,int l,int r,int up,int d){
    112     if(tl >= l && tr <= r && d == 1){
    113         if(minn[now] < up){
    114         while(tl != tr){
    115             int mid = (tl+tr)/2;
    116             if(minn[now<<1|1] < up) tl = mid+1,now=now*2+1;
    117             else tr = mid,now<<=1;
    118         }
    119         return make_pair(minn[now],tl);
    120         }else return make_pair(0,0);
    121     }
    122     if(tl >= l && tr <= r && d == 0){
    123         if(minn[now] < up){
    124         while(tl != tr){
    125             int mid = (tl+tr)/2;
    126             if(minn[now<<1] < up) tr = mid,now<<=1;
    127             else tl = mid+1,now=now*2+1;
    128         }
    129         return make_pair(minn[now],tl);
    130         }else return make_pair(0,0);
    131     }
    132     if(tl > r || tr < l) return make_pair(0,0);
    133     int mid = (tl+tr)/2;
    134     if(mid>=r) return QueryRange(now<<1,tl,mid,l,r,up,d);
    135     if(mid<l) return QueryRange(now<<1|1,mid+1,tr,l,r,up,d);
    136     if(d){
    137         pair<int,int> z = QueryRange(now<<1|1,mid+1,tr,l,r,up,d);
    138         if(z.first) return z;
    139         else return QueryRange(now<<1,tl,mid,l,r,up,d);
    140     }else{
    141         pair<int,int> z = QueryRange(now<<1,tl,mid,l,r,up,d);
    142         if(z.first) return z;
    143         else return QueryRange(now<<1|1,mid+1,tr,l,r,up,d);
    144     }
    145     }
    146     void add(int now,int tl,int tr,int pos,int dt){
    147     if(tl == tr) {minn[now] = dt;return;}
    148     int mid = (tl+tr)/2;
    149     if(pos <= mid) add(now<<1,tl,mid,pos,dt);
    150     else add(now<<1|1,mid+1,tr,pos,dt);
    151     minn[now] = min(minn[now<<1],minn[now<<1|1]);
    152     }
    153     
    154     void holyshit(){
    155     memset(minn,0x3f,sizeof(minn));
    156     for(int i=n-1;i>=0;i--){
    157         int z = rk[i],p=19260817;
    158         add(1,1,n,z,i);
    159         while(true){
    160         pair<int,int> um = QueryRange(1,1,n,z+1,n,p,0);
    161         if(!um.first) break;
    162         mlgb[um.first].push_back(i);
    163         z = um.second; p = sa[z];
    164         }
    165         z = rk[i],p = 19260817;
    166         while(true){
    167         pair<int,int> um = QueryRange(1,1,n,1,z-1,p,1);
    168         if(!um.first) break;
    169         mlgb[um.first].push_back(i);
    170         z = um.second; p = sa[z];
    171         }
    172     }
    173     
    174     }
    175 }
    176 
    177 void work(){
    178     GetSA();
    179     GetHeight();
    180     buildRMQ();
    181     
    182     BruteForce::holyshit();
    183     int num = 1;
    184     for(int i=0;i<n;i++){
    185     for(int j=0;j<mlgb[i].size();j++){
    186         int z = LCP(mlgb[i][j],i);
    187         if(a[mlgb[i][j]] >= z) continue;
    188         a[mlgb[i][j]] = z;
    189         update(1,0,n-1,mlgb[i][j],z);
    190         
    191     }
    192     while(qy[num].r == i){
    193         int z = 0,pq = qy[num].r-1;
    194         while(pq >= qy[num].l){
    195         int hp = Query(1,0,n-1,0,pq,z);
    196         if(hp < qy[num].l) hp = qy[num].l-1;
    197         ans[qy[num].nb] += (pq-hp)*z;
    198         if(hp < 0) break;
    199         z = a[hp],pq = hp;
    200         }
    201         num++;
    202     }
    203     }
    204     for(int i=1;i<=q;i++) printf("%d
    ",ans[i]);
    205 }
    206 
    207 int cmp(node alpha,node beta){return alpha.r < beta.r;}
    208 int main(){
    209     //freopen("1.in","r",stdin);
    210     fstread(n);fstread(q);
    211     for(int i=1;i<=n;i++){
    212     str[i-1] = getchar();
    213     while(str[i-1]!= '0' && str[i-1] != '1') str[i-1] = getchar();
    214     }
    215     for(int i=1;i<=q;i++) fstread(qy[i].l),fstread(qy[i].r),qy[i].nb=i;
    216     for(int i=1;i<=q;i++) qy[i].l--,qy[i].r--;
    217     sort(qy+1,qy+q+1,cmp);
    218     work();
    219     return 0;
    220 }
  • 相关阅读:
    C51中的 xbyte的使用
    使用正则表达式替换日期格式
    C#制作windows窗体的图书管理系统
    《短码之美》读书笔记3
    VS2019创建第一个ASP.NET网站
    观影大数据分析(上)
    Git提交文件报错解决
    软件设计简单工厂模式
    记录一次MySQL启动异常的解决
    将本机web项目映射到公网访问
  • 原文地址:https://www.cnblogs.com/Menhera/p/10555157.html
Copyright © 2011-2022 走看看