码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 4556: [Tjoi2016&Heoi2016]字符串

时间:2017-01-12 21:31:52      阅读:497      评论:0      收藏:0      [点我收藏+]

标签:while   sum   pac   line   har   names   get   swa   二分   

      二分ans,二分区间长度,st表查,最后主席树判断。

      这题最大收获学到了一个nb的卡常技巧,主席树元素个数为0直接返回,不敢相信快了一倍。

    

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #define N 200005
  6 using namespace std;
  7 inline int read()
  8 {
  9     int p=0;char c=getchar();
 10     while(c<0||c>9)c=getchar();
 11     while(c>=0&&c<=9)p=p*10+c-0,c=getchar();
 12     return p;
 13 }
 14 int wb[N],rank[N],sa[N],sum[N];
 15 int mnn(int x,int y)
 16 {
 17     if(x<y)return x;return y;
 18 }
 19 char s[N];
 20 void da(int n,int m)
 21 {
 22     int *x=rank,*y=wb;
 23     for(int i=0;i<m;i++)sum[i]=0;
 24     for(int i=0;i<n;i++)sum[x[i]=s[i]]++;
 25     for(int i=1;i<m;i++)sum[i]+=sum[i-1];
 26     for(int i=n-1;i>=0;i--)sa[--sum[x[i]]]=i;
 27     int p=1;
 28     for(int j=1;p<n;j<<=1,m=p)
 29     {
 30         p=0;
 31         for(int i=n-j;i<n;i++)y[p++]=i;
 32         for(int i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
 33         for(int i=0;i<m;i++)sum[i]=0;
 34         for(int i=0;i<n;i++)sum[x[i]]++;
 35         for(int i=1;i<m;i++)sum[i]+=sum[i-1];
 36         for(int i=n-1;i>=0;i--)sa[--sum[x[y[i]]]]=y[i];
 37         swap(x,y);x[sa[0]]=0;p=1;
 38         for(int i=1;i<n;i++)
 39          x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;
 40     }
 41     return ;
 42 }
 43 int h[N];
 44 void cal(int n)
 45 {
 46     int k=0;
 47     for(int i=1;i<=n;i++)rank[sa[i]]=i;
 48     for(int i=0;i<n;i++)
 49     {
 50         if(k)k--;
 51         int j=sa[rank[i]-1];
 52         while(s[j+k]==s[i+k])k++;
 53         h[rank[i]]=k;
 54     }
 55 }
 56 int n,m;
 57 int mn[N][20];
 58 int lg[N];
 59 int root[N];
 60 void st()
 61 {
 62     int now=0;
 63     for(int i=1;i<=n;i<<=1)
 64     {
 65         for(int j=i;j<i<<1;j++)
 66         {
 67             lg[j]=now;
 68         }
 69         now++;
 70     }
 71     for(int i=1;i<=n;i++)mn[i][0]=h[i];
 72     for(int i=1;i<=18;i++)
 73     {
 74         int k=(1<<(i-1));
 75         for(int j=1;j<=n;j++)
 76         {
 77             if(j+k<=n)mn[j][i]=mnn(mn[j][i-1],mn[j+k][i-1]);
 78             else mn[j][i]=mn[j][i-1];
 79         }
 80     }return ;
 81 }
 82 struct node
 83 {
 84     int l,r,sum;
 85 }a[N*20];int cnt;
 86 void merge(int x,int y,int l,int r,int pos)
 87 {
 88     if(l==r)
 89     {
 90         a[x].sum=1;
 91         return ;
 92     }
 93     int mid=(l+r)>>1;
 94     if(pos<=mid)
 95     {
 96         a[x].l=++cnt;
 97         a[x].r=a[y].r;
 98         merge(a[x].l,a[y].l,l,mid,pos);
 99     }
100     else
101     {
102         a[x].r=++cnt;
103         a[x].l=a[y].l;
104         merge(a[x].r,a[y].r,mid+1,r,pos);
105     }
106     a[x].sum=a[a[x].l].sum+a[a[x].r].sum;
107 }
108 bool qur(int x,int y,int l,int r,int ll,int rr)
109 {
110     if(a[x].sum==a[y].sum)return 0;
111     if(l>=ll&&r<=rr)return a[x].sum!=a[y].sum;
112     int mid=(l+r)>>1;
113     if(ll<=mid)if(qur(a[x].l,a[y].l,l,mid,ll,rr))return 1;
114     if(rr>mid)if(qur(a[x].r,a[y].r,mid+1,r,ll,rr))return 1;
115     return 0;
116 }
117 int t1,t2,t3,t4;
118 inline int qr(int l,int r)
119 {
120     if(l>r)return N;
121     int k=lg[r-l+1];
122     return mnn(mn[l][k],mn[r-(1<<k)+1][k]);
123 }
124 bool pan(int x)
125 {
126      int pos=rank[t3-1];
127      int ll,rr;
128      int l=pos,r=n,mid;
129      while(l<=r)
130      {
131          mid=(l+r)>>1;
132          if(qr(pos+1,mid)<x)r=mid-1;
133          else l=mid+1;
134      }
135      rr=r;
136      l=1,r=pos;
137      while(l<=r)
138      {
139          mid=(l+r)>>1;
140          if(qr(mid+1,pos)<x)l=mid+1;
141          else r=mid-1;
142      }
143      ll=l;
144      return qur(root[rr],root[ll-1],1,n,t1,t2-x+1);
145 }
146 
147 int main()
148 {
149     scanf("%d%d",&n,&m);
150     scanf("%s",s);
151     da(n+1,256);cal(n);
152     st();
153     for(int i=1;i<=n;i++)
154     {
155         root[i]=++cnt;
156         merge(root[i],root[i-1],1,n,sa[i]+1);
157     }
158     for(int i=1;i<=m;i++)
159     {
160         t1=read();t2=read();t3=read();t4=read();
161         int l=0;int r=min(t2-t1+1,t4-t3+1);
162         while(l<=r)
163         {
164             int mid=(l+r)>>1;
165             if(pan(mid))l=mid+1;
166             else r=mid-1;
167         }
168         printf("%d\n",r);
169     }
170     return 0;
171 }
172 /*
173 5 2
174 ababaa
175 1 4 2 5
176 1 4 2 3
177 */

 

bzoj 4556: [Tjoi2016&Heoi2016]字符串

标签:while   sum   pac   line   har   names   get   swa   二分   

原文地址:http://www.cnblogs.com/ezyzy/p/6279658.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!