bzoj5253 [2018多省省队联测]制胡窜

后缀自动机挺好毒瘤的题。

我们考虑哪些切点是不合法的。肯定是所有的匹配串都被切了。

我们考虑第一个切口的位置。

当第一个切口在第一个出现位置前时,第二个切口必须切掉所有的串。

当第一个切口在$l_{i}$和$l_{i+1}$间的时候(此时必须保证切掉第一个串),第二个切口必须切掉$s_{i+1}$到$s_{cnt}$这些串

当第一个切口在$l_{cnt}$后时(此时依旧需要保证切掉第一个串),第二个切口随便放。

于是我们将询问离线,对于每个询问通过在parent树上倍增来找到所对应的节点。

对于后缀自动机上每个节点,通过平衡树启发式合并来维护他的right集合,之后我们只需要维护$\sum{(l_{i+1}-l_{i}) \cdot (r_{i+1}-l_{cnt})}$即可,然后拆开式子,就是$\sum{(r_{i+1}-r_{i}) \cdot r_{i+1}}$和$\sum{r_{i+1}-r_{i}}$。

因为每个询问的长度不同,又因为我们在上述第二三种情况都需要保证切掉第一个串,所以我们所需要提取的区间也不同,这个我们直接在平衡树上乱搞一下就可以了。

之后我们就可以愉快的AC掉这道好毒瘤题啦!

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <vector>
  7 #define N 100500
  8 #define LL long long
  9 using namespace std;
 10  
 11 int n,m;
 12 char s[N];
 13 struct data{
 14     int l,r;
 15     LL ans;
 16 }d[300500];
 17 vector <int> V[N<<1];
 18  
 19 #define siz(_) ((!(_))?(0):((_)->size))
 20 #define tp pair<Treap *,Treap *>
 21 struct Treap{
 22     Treap *ch[2];
 23     int key,size,val,maxn,minn,val2,sum2;
 24     LL val1,sum1;
 25     //sum1=(r[i+1]-r[i])*r[i+1];
 26     //sum2=(r[i+1]-r[i]);
 27     Treap(int x){
 28         val=maxn=minn=x;
 29         key=rand();size=1;
 30         sum1=val1=sum2=val2=0;
 31         ch[0]=ch[1]=NULL;
 32     }
 33     void pushup(){
 34         size=siz(ch[0])+siz(ch[1])+1;
 35         minn=maxn=val;
 36         sum1=val1;sum2=val2;
 37         if(ch[0]){
 38             minn=ch[0]->minn;
 39             sum1+=ch[0]->sum1;
 40             sum2+=ch[0]->sum2;
 41         }
 42         if(ch[1]){
 43             maxn=ch[1]->maxn;
 44             sum1+=ch[1]->sum1;
 45             sum2+=ch[1]->sum2;
 46         }
 47     }
 48 }*root[N<<1];
 49  
 50 Treap *merge(Treap *a,Treap *b){
 51     if(!a)return b;
 52     if(!b)return a;
 53     if(a->key<=b->key){
 54         a->ch[1]=merge(a->ch[1],b);
 55         a->pushup();return a;
 56     }
 57     else{
 58         b->ch[0]=merge(a,b->ch[0]);
 59         b->pushup();return b;
 60     }
 61 }
 62 tp split(Treap *a,int k){
 63     if(!a)return tp(NULL,NULL);
 64     tp x;
 65     if(siz(a->ch[0])>=k){
 66         x=split(a->ch[0],k);
 67         a->ch[0]=x.second;
 68         a->pushup();x.second=a;
 69     }
 70     else{
 71         x=split(a->ch[1],k-siz(a->ch[0])-1);
 72         a->ch[1]=x.first;
 73         a->pushup();x.first=a;
 74     }
 75     return x;
 76 }
 77 int getrank(Treap *rt,int x){
 78     int k=0;
 79     while(1){
 80         if(!rt)return k;
 81         if(rt->val<x)k+=siz(rt->ch[0])+1,rt=rt->ch[1];
 82         else rt=rt->ch[0];
 83     }
 84 }
 85 void insert(Treap *&rt,int x){
 86     int k=getrank(rt,x);
 87     tp t=split(rt,k);
 88     Treap *now=new Treap(x);
 89     if(t.first){
 90         tp w=split(t.first,k-1);
 91         now->val1=now->sum1=1ll*(x-w.second->val)*x;
 92         now->val2=now->sum2=(x-w.second->val);
 93         t.first=merge(w.first,w.second);
 94     }
 95     if(t.second){
 96         tp w=split(t.second,1);
 97         w.first->val1=w.first->sum1=1ll*(w.first->val-x)*w.first->val;
 98         w.first->val2=w.first->sum2=(w.first->val-x);
 99         t.second=merge(w.first,w.second);
100     }
101     rt=merge(merge(t.first,now),t.second);
102 }
103 void dfs(Treap *o,Treap *&rt){
104     if(!o)return ;
105     dfs(o->ch[0],rt);
106     insert(rt,o->val);
107     dfs(o->ch[1],rt);
108 }
109 int find1(Treap *rt,int x){
110     if(rt==NULL)return 0;
111     if(rt->val>=x)return find1(rt->ch[0],x);
112     else{
113         if(!rt->ch[1]||rt->ch[1]->minn>=x)return rt->val;
114         return find1(rt->ch[1],x);
115     }
116 }
117 int find2(Treap *rt,int x){
118     if(rt==NULL)return 0;
119     if(rt->val<=x)return find2(rt->ch[1],x);
120     else{
121         if(!rt->ch[0]||rt->ch[0]->maxn<=x)return rt->val;
122         return find2(rt->ch[0],x);
123     }
124 }
125 void query(Treap *rt,int x,LL &s1,int &s2){
126     if(!rt)return ;
127     if(rt->val<=x){
128         if(rt->ch[0])s1+=rt->ch[0]->sum1,s2+=rt->ch[0]->sum2;
129         s1+=rt->val1,s2+=rt->val2;
130         query(rt->ch[1],x,s1,s2);
131     }
132     else query(rt->ch[0],x,s1,s2);
133 }
134 LL query(int x,int l){
135     LL ans=0;
136     int r1=root[x]->minn,r2=root[x]->maxn;
137     if(r2-l+1<r1){
138         ans+=1ll*(r1-l)*(r1-(r2-l+1));
139         ans+=1ll*(n-(r2-l)-2+n-r1)*(r1-r2+l-1)/2;
140     }
141     int pos1=find1(root[x],r2-l+1);
142     int pos2=find2(root[x],r1+l-2);
143     if(!pos2)pos2=r2;
144     LL sum1=0,sum2=0;
145     int size1=0,size2=0;
146     query(root[x],pos1,sum1,size1);
147     query(root[x],pos2,sum2,size2);
148     if(pos2>pos1){
149         ans+=sum2-sum1;
150         ans-=1ll*(r2-l+1)*(size2-size1);
151         if(pos2-l+1>r1)ans-=1ll*((pos2-l+1)-r1)*(pos2-(r2-l+1));
152     }
153     return ans;
154 }
155 int last[N],tot,mx[N<<1],ch[N<<1][11],par[N<<1];
156  
157 void extend(int x,int c){
158     int p=last[x-1],np=++tot;
159     mx[np]=mx[p]+1;
160     root[np]=NULL;
161     insert(root[np],x);
162     for(;p&&!ch[p][c];p=par[p])ch[p][c]=np;
163     if(!p) par[np]=1;
164     else{
165         int q=ch[p][c];
166         if(mx[q]==mx[p]+1)par[np]=q;
167         else{
168             int nq=++tot;
169             par[nq]=par[q];
170             memcpy(ch[nq],ch[q],sizeof ch[nq]);
171             mx[nq]=mx[p]+1;
172             root[nq]=NULL;
173             par[q]=par[np]=nq;
174             for(;p&&ch[p][c]==q;p=par[p])ch[p][c]=nq;
175         }
176     }
177     last[x]=np;
178 }
179 int e=1,head[N<<1];
180 struct edge{
181     int v,next;
182 }ed[N<<1];
183 void add(int u,int v){
184     ed[e].v=v;ed[e].next=head[u];
185     head[u]=e++;
186 }
187 int fa[N<<1][22];
188 void dfs(int x,int d){
189     for(int i=1;(1<<i)<=d;i++)
190         fa[x][i]=fa[fa[x][i-1]][i-1];
191     for(int i=head[x];i;i=ed[i].next){
192         fa[ed[i].v][0]=x;
193         dfs(ed[i].v,d+1);
194     }
195 }
196 int find(int x,int l){
197     for(int i=17;~i;i--)
198         if(mx[fa[x][i]]>=l)x=fa[x][i];
199     return x;
200 }
201 void dfs(int x){
202     for(int i=head[x];i;i=ed[i].next){
203         dfs(ed[i].v);
204         if(siz(root[ed[i].v])>siz(root[x]))swap(root[x],root[ed[i].v]);
205         dfs(root[ed[i].v],root[x]);
206     }
207     for(int i=0;i<V[x].size();i++){
208         int now=V[x][i];
209         d[now].ans=query(x,d[now].r-d[now].l+1);
210     }
211 }
212 int main(){
213     scanf("%d%d",&n,&m);
214     scanf("%s",s+1);
215     last[0]=++tot;
216     for(int i=1;i<=n;i++)extend(i,s[i]-'0');
217     for(int i=2;i<=tot;i++)add(par[i],i);
218     dfs(1,1);
219     for(int i=1,x;i<=m;i++){
220         scanf("%d%d",&d[i].l,&d[i].r);
221         x=find(last[d[i].r],d[i].r-d[i].l+1);
222         V[x].push_back(i);
223     }
224     dfs(1);
225     LL all=1ll*(n-1)*(n-2)/2;
226     for(int i=1;i<=m;i++){
227         d[i].ans=all-d[i].ans;
228         printf("%lld\n",d[i].ans);
229     }
230     return 0;
231 }
View Code

 

posted @ 2018-04-10 19:49  Ren_Ivan  阅读(238)  评论(0编辑  收藏  举报