• 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
    ",d[i].ans);
    229     }
    230     return 0;
    231 }
    View Code
  • 相关阅读:
    SPRING IN ACTION 第4版笔记-第九章Securing web applications-008-使用非关系型数据库时如何验证用户(自定义UserService)
    [转]苹果商店审核规则,你触犯了哪一条?
    Xcode itunes完美打包api方法
    Swift中构造器的继承和重写
    Swift中类的两段式构造(类的构造过程)
    Swift中的便利构造器和构造器链
    iOS在UITableViewController里使用UISearchDisplayController报错"[UISearchResultsTableView dequeueReusableCellWithIdentifier:forIndexPath:]"
    Swift缩水版MJExtension
    构造器相关
    可选链
  • 原文地址:https://www.cnblogs.com/Ren-Ivan/p/8782073.html
Copyright © 2020-2023  润新知