1. 程式人生 > >[BZOJ4556][Tjoi2016&Heoi2016]字符串 後綴數組+主席樹

[BZOJ4556][Tjoi2016&Heoi2016]字符串 後綴數組+主席樹

main har 箱子 nlog 表示 query out namespace mini

4556: [Tjoi2016&Heoi2016]字符串

Time Limit: 20 Sec Memory Limit: 128 MB

Description

佳媛姐姐過生日的時候,她的小夥伴從某東上買了一個生日禮物。生日禮物放在一個神奇的箱子中。箱子外邊寫了 一個長為n的字符串s,和m個問題。佳媛姐姐必須正確回答這m個問題,才能打開箱子拿到禮物,升職加薪,出任CE O,嫁給高富帥,走上人生巔峰。每個問題均有a,b,c,d四個參數,問你子串s[a..b]的所有子串和s[c..d]的最長公 共前綴的長度的最大值是多少?佳媛姐姐並不擅長做這樣的問題,所以她向你求助,你該如何幫助她呢?

Input

輸入的第一行有兩個正整數n,m,分別表示字符串的長度和詢問的個數。接下來一行是一個長為n的字符串。接下來 m行,每行有4個數a,b,c,d,表示詢問s[a..b]的所有子串和s[c..d]的最長公共前綴的最大值。1<=n,m<=100,000, 字符串中僅有小寫英文字母,a<=b,c<=d,1<=a,b,c,d<=n

Output

對於每一次詢問,輸出答案。

Sample Input

5 5
aaaaa
1 1 1 5
1 5 1 1
2 3 2 3
2 4 2 3
2 3 2 4

Sample Output

1
1
2
2
2
題解: 真是太刺激了。。第一次發現後綴數組可以和高級數據結構聯系起來233 (不過據說正解並不是裸跑後綴數組……) 首先,我們容易想到二分答案求解,但是二分之後怎麽處理呢? 我們考慮,對於這個二分的長度x,rank[c]附近一定可以形成一段區間,使得他們的lcp大於等於x(rank[c]自己的lcp是串長) 這一段區間的查詢我們可以通過ST表進行查詢 接下來,如果[a,b]範圍內有一個串存在於那個區間裏就好了, 那麽我們考慮,如何查詢某個區間內的一些給定值是否出現某個值呢? 這種查詢的特點不難讓我們想到主席樹"切割區間"的功能:
即查詢a到b-x+1(如果x等於0,那麽這個端點是b)區間內是否有一個rank值處在剛才查找到的區間, 我們可以通過主席樹這種權值線段樹記錄這個存在性問題 這樣不斷判斷合法性即可,復雜度是nlogn預處理+mlog2n查詢的,因此可以AC. 代碼實現:
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 using namespace std;
  5 const int N=100010;
  6 int cnt[N],xx[N],yy[N],n;
  7 char s[N];
  8 int rank[N],sa[N],height[N],bin[20],f[N][18];
  9 inline void get_sa(int m)
 10 {
 11     int *x=xx,*y=yy;
 12     register int i,j,p,k;
 13     for(i=0;i<m;++i)cnt[i]=0;
 14     for(i=0;i<n;++i)++cnt[x[i]=s[i]];
 15     for(i=1;i<m;++i)cnt[i]+=cnt[i-1];
 16     for(i=n-1;~i;--i)sa[--cnt[x[i]]]=i;
 17     for(k=1,p=0;k<=n&&p<n;k<<=1,m=p)
 18     {
 19         for(p=0,i=n-k;i<n;++i)y[p++]=i;
 20         for(i=0;i<n;++i)if(sa[i]>=k)y[p++]=sa[i]-k;
 21         for(i=0;i<m;++i)cnt[i]=0;
 22         for(i=0;i<n;++i)++cnt[x[y[i]]];
 23         for(i=1;i<m;++i)cnt[i]+=cnt[i-1];
 24         for(i=n-1;~i;--i)sa[--cnt[x[y[i]]]]=y[i];
 25         swap(x,y),x[sa[0]]=0,p=1;
 26         for(i=1;i<n;++i)
 27             x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?p-1:p++;
 28     }
 29 }
 30 inline void get_height()
 31 {
 32     register int i,j,k;
 33     for(i=0;i<n;++i)rank[sa[i]]=i;
 34     for(k=i=0;i<n;height[rank[i++]]=k)
 35         for(k=k?k-1:k,j=sa[rank[i]-1];s[i+k]==s[j+k];++k);
 36 }
 37 inline void ST()
 38 {
 39     register int i,j;
 40     for(bin[0]=i=1;i<=18;++i)
 41         bin[i]=bin[i-1]<<1;
 42     for(j=0;j<n;++j)f[j][0]=height[j];
 43     for(i=1;bin[i-1]<=n;++i)
 44         for(j=0;j+bin[i]<=n;++j)
 45             f[j][i]=min(f[j][i-1],f[j+bin[i-1]][i-1]);
 46 }
 47 struct node
 48 {
 49     node *ch[2];int cnt;
 50     node(){ch[0]=ch[1]=NULL;cnt=0;}
 51     inline void update(){cnt=ch[0]->cnt+ch[1]->cnt;}
 52 }*null=new node(),*root[N];
 53 inline node* newnode()
 54     {node *o=new node();o->ch[1]=o->ch[0]=null;return o;}
 55 inline bool query(node *a,node *b,int L,int R,int l,int r)
 56 {
 57     if(L<=l&&r<=R)return b->cnt-a->cnt;
 58     int mi=l+r>>1;bool ret=0;
 59     if(L<=mi)ret|=query(a->ch[0],b->ch[0],L,R,l,mi);
 60     if(mi<R)ret|=query(a->ch[1],b->ch[1],L,R,mi+1,r);
 61     return ret;
 62 }
 63 inline void get_range(int val,int &l,int &r)
 64 {
 65     register int j;
 66     for(j=17;~j&&r<n;--j)
 67         if(r+bin[j]-1<n&&f[r+1][j]>=val)r+=bin[j];
 68     for(j=17;~j&&l;--j)
 69         if(l-bin[j]+1>=0&&f[l-bin[j]+1][j]>=val)l-=bin[j];
 70 }
 71 inline bool judge(int a,int b,int c,int minimum)
 72 {
 73     int l=rank[c],r=rank[c],right=minimum?b-minimum+1:b;
 74     get_range(minimum,l,r);
 75     if(query(a?root[a-1]:null,root[right],l,r,0,n-1))return 1;
 76     return 0;
 77 }
 78 inline void insert(node *&o,node *old,int l,int r,int pos)
 79 {
 80     o->cnt=old->cnt+1;int mi=(l+r)>>1;if(l==r)return;
 81     if(pos<=mi)
 82         o->ch[1]=old->ch[1],o->ch[0]=newnode(),
 83         insert(o->ch[0],old->ch[0],l,mi,pos);
 84     else 
 85         o->ch[0]=old->ch[0],o->ch[1]=newnode(),
 86         insert(o->ch[1],old->ch[1],mi+1,r,pos);
 87     o->update();
 88 }
 89 inline void Tree_intn()
 90 {
 91     register int i;
 92     null->ch[0]=null->ch[1]=null;
 93     for(i=0;i<n;++i)root[i]=newnode();
 94     insert(root[0],null,0,n-1,rank[0]);
 95     for(i=1;i<n;++i)
 96         insert(root[i],root[i-1],0,n-1,rank[i]);
 97 }
 98 int main()
 99 {
100     register int i,j,k,a,b,c,d,m,l,mi,r,ans;
101     scanf("%d%d%s",&n,&m,s),s[n++]=1,
102     get_sa(256),get_height(),ST(),Tree_intn();
103     while(m--)
104     {
105         scanf("%d%d%d%d",&a,&b,&c,&d),--a,--b,--c,--d;
106         l=0,mi,r=min(b-a+1,d-c+1),ans=0;
107         while(l<=r)
108             if(judge(a,b,c,(mi=l+r>>1)))l=mi+1,ans=mi;
109             else r=mi-1;
110         printf("%d\n",ans);
111     }
112 }

[BZOJ4556][Tjoi2016&Heoi2016]字符串 後綴數組+主席樹