zoukankan      html  css  js  c++  java
  • bzoj4199

    看到这题我就伤心,当初想到了正解却因为各种sb原因没有写……

    好吧,其实我的正解是比较挫的……

    大家似乎都用了后缀数组,我用了后缀自动机(后缀树)

    其实SAM是很好想得,用SAM建出后缀树后

    我们考虑树上每个节点对答案的贡献,0相似就不必说了

    考虑到任意两个后缀的LCP即这两个后缀所在节点的LCA的节点所能接受的最长子串mx[i]

    又每个节点能接收的子串长度为[mx[fa[i]]+1,mx[i]]

    我们很容易想出问题1:设节点i的子树内代表后缀的节点个数为s,那么节点i对区间[mx[fa[i]]+1,mx[i]]贡献是s*(s-1)/2

    问题2:很显然找出节点i子树内max{最大*次大,最小*次小}(因为有负数),这要dfs序+线段树维护,然后区间覆盖再来个线段树……

    总复杂度是O(nlogn),实际是能过的(但是跑得似乎比SA做法慢……)

      1 #include<iostream>
      2 #include<cmath>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<stdlib.h>
      6 #define ll long long
      7 #define N 300005
      8 using namespace std;
      9 const ll inf=-1000000001;
     10 const ll small=-1000000002000000001ll;
     11 int go[2*N][26],fa[2*N],w[2*N],mx[2*N],p[2*N],a[2*N],b[2*N],l[2*N],r[2*N];
     12 struct node{ll b1,b2,s1,s2;} tree[8*N];
     13 struct way{int po,next;} e[2*N];
     14 ll ans[4*N][2];
     15 int n,last,t,len;
     16 char s[N];
     17 
     18 void ins(int x,int y)
     19 {
     20      e[++len].po=y;
     21      e[len].next=p[x];
     22      p[x]=len;
     23 }
     24      
     25 void add(int c,int x)
     26 {
     27      int np,nq,q,p=last;
     28      np=++t; mx[np]=mx[p]+1; a[np]=x; w[np]=1;
     29      for (;p&&!go[p][c];p=fa[p]) go[p][c]=np;
     30      if (!p) fa[np]=1;
     31      else {
     32           q=go[p][c];
     33           if (mx[q]==mx[p]+1) fa[np]=q;
     34           else {
     35                nq=++t; a[t]=inf;
     36                mx[nq]=mx[p]+1;
     37                memcpy(go[nq],go[q],sizeof(go[q]));
     38                fa[nq]=fa[q]; fa[np]=fa[q]=nq;
     39                for (;go[p][c]==q;p=fa[p]) go[p][c]=nq;
     40           }
     41      }
     42      last=go[last][c];
     43 }
     44 
     45 void dfs(int x)
     46 {
     47      l[x]=++t; b[t]=x; 
     48      for (int i=p[x];i;i=e[i].next)
     49      {
     50          int y=e[i].po;
     51          dfs(y); w[x]+=w[y];
     52      }
     53      r[x]=t;
     54 }
     55  
     56 void update(node &a,node x,node y)
     57 {
     58      if (x.b1>y.b1) 
     59      {
     60         a.b1=x.b1;
     61         a.b2=max(x.b2,y.b1);
     62      }         
     63      else {
     64           a.b1=y.b1;
     65           a.b2=max(x.b1,y.b2);
     66      } 
     67      if (x.s1>y.s1)
     68      {
     69         a.s1=y.s1;
     70         a.s2=min(x.s1,y.s2);
     71      }
     72      else {
     73           a.s1=x.s1;
     74           a.s2=min(x.s2,y.s1);
     75      }   
     76 }
     77 void build(int i,int l, int r)
     78 {
     79      if (l==r)
     80      {
     81         tree[i].b1=a[b[l]];
     82         tree[i].b2=inf; 
     83         tree[i].s2=-inf;
     84         tree[i].s1=(a[b[l]]==inf)?-inf:a[b[l]];
     85         return;
     86      }         
     87      int m=(l+r)>>1;
     88      build(i*2,l,m);
     89      build(i*2+1,m+1,r);
     90      update(tree[i],tree[i*2],tree[i*2+1]);
     91 }
     92 
     93 node get(int i,int l,int r,int x, int y)
     94 {
     95      if (x<=l&&y>=r) return tree[i];
     96      int m=(l+r)>>1;
     97      node s,b,c; 
     98      b.b1=b.b2=c.b1=c.b2=inf; 
     99      b.s1=b.s2=c.s1=c.s2=-inf;
    100      if (x<=m) b=get(i*2,l,m,x,y);
    101      if (y>m) c=get(i*2+1,m+1,r,x,y);
    102      update(s,b,c);
    103      return s;
    104 }
    105 
    106 void work(int i,int l,int r,int x,int y,ll a,ll b)
    107 {
    108      if (x<=l&&y>=r) {ans[i][0]+=a; ans[i][1]=max(ans[i][1],b);}
    109      else {
    110           int m=(l+r)>>1;
    111           if (ans[i][0]) 
    112           {
    113              ans[i*2][0]+=ans[i][0]; ans[i*2+1][0]+=ans[i][0];
    114              ans[i][0]=0;
    115           }
    116           if (ans[i][1]>small) 
    117           {
    118              ans[i*2][1]=max(ans[i][1],ans[i*2][1]); ans[i*2+1][1]=max(ans[i][1],ans[i*2+1][1]);
    119              ans[i][1]=small;
    120           }
    121           if (x<=m) work(i*2,l,m,x,y,a,b);
    122           if (y>m) work(i*2+1,m+1,r,x,y,a,b);
    123      }
    124 }  
    125 
    126 void getans(int i,int l,int r)
    127 {
    128      if (l==r) 
    129      {
    130          if (ans[i][0]==0) ans[i][1]=0;
    131          printf("%lld %lld
    ",ans[i][0],ans[i][1]);
    132      }
    133      else {
    134           int m=(l+r)>>1;
    135           if (ans[i][1]>small) {ans[i*2][1]=max(ans[i][1],ans[i*2][1]); ans[i*2+1][1]=max(ans[i][1],ans[i*2+1][1]);}
    136           if (ans[i][0]) {ans[i*2][0]+=ans[i][0]; ans[i*2+1][0]+=ans[i][0];}
    137           getans(i*2,l,m);
    138           getans(i*2+1,m+1,r);
    139      }
    140 }
    141      
    142 int main()
    143 {   
    144     scanf("%d",&n); scanf("%s",s+1);
    145     for (int i=1; i<=n; i++) scanf("%d",&b[i]);
    146     if (n==1) {puts("0 0");return 0;}
    147     t=last=1; a[1]=inf;
    148     for (int i=n;i;i--) add(s[i]-'a',b[i]);
    149     for (int i=2;i<=t; i++) ins(fa[i],i);
    150     t=0; dfs(1);
    151     build(1,1,t);   
    152     for (int i=1; i<=n*4;i++) ans[i][1]=small;    
    153     for (int i=2; i<=t; i++) 
    154     {   
    155         if (w[i]<=1) continue;
    156         node c=get(1,1,t,l[i],r[i]);
    157         ll x=max(c.b1*c.b2,c.s1*c.s2);
    158         work(1,1,n-1,mx[fa[i]]+1,mx[i],(ll)(w[i]-1)*(ll)(w[i])/2,x);
    159     }
    160     printf("%lld %lld
    ",(ll)(w[1]-1)*(ll)(w[1])/2,max(tree[1].b1*tree[1].b2,tree[1].s1*tree[1].s2));
    161     getans(1,1,n-1);
    162     return 0;
    163 }
    164     
    View Code
  • 相关阅读:
    Markdown编辑器语法指南2
    python文件读写的学习
    K:图相关的最小生成树(MST)
    K:哈弗曼树
    K:树、二叉树与森林之间的转换及其相关代码实现
    K:二叉树
    K:树与二叉树
    KandQ:那年,那树,那些知识点
    K:java中的安全模型(沙箱机制)
    K:java中的RMI(Remote Method Invocation)
  • 原文地址:https://www.cnblogs.com/phile/p/5658558.html
Copyright © 2011-2022 走看看