1. 程式人生 > >BZOJ 4199 [Noi2015]品酒大會:後綴數組 + 並查集

BZOJ 4199 [Noi2015]品酒大會:後綴數組 + 並查集

更新 pre 最大 gpo 每次 for 可能 sin string

題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=4199

題意:

  給你一個長度為n的字符串s,和一個長為n的數組v。

  對於每個整數r∈[0,n-1]:

    (1)問你有多少對後綴(suffix(i), suffix(j)),滿足LCP(suffix(i), suffix(j)) >= r

    (2)輸出mul[r] = max(v[i]*v[j]),其中i,j滿足(1)的條件

題解:

  先考慮第(1)問。

  由於LCP只受連續的一段height中最小值的影響

  所以先將height數組排序,然後按height從大到小的順序,合並當前height對應的兩個後綴suffix(i)和suffix(j)所在的集合。

  那麽對於任意兩個分別屬於這兩個集合的後綴來說,它們的LCP一定為當前height。

  假設ans[r]表示LCP恰好為r的後綴對個數,那麽此時的貢獻為ans[height] += siz[find(i)] * siz[find(j)]

  最後對ans數組求一遍後綴和,即為LCP >= r的後綴對個數。

  然後再考慮第(2)問。

  由於v[i]有可能為負值,所以對於每個集合,維護集合中元素對應v[i]的最大值和最小值。

  那麽每次合並時,用max(兩個集合的最大值之積,最小值之積)更新mul[par]即可。

AC Code:

  1 #include <iostream>
  2
#include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 #define MAX_N 300005 6 7 using namespace std; 8 9 struct Height 10 { 11 int v,id; 12 Height(int _v,int _id) 13 { 14 v=_v; id=_id; 15 } 16 Height(){} 17 friend bool
operator < (const Height &a,const Height &b) 18 { 19 return a.v<b.v; 20 } 21 }; 22 23 int n; 24 int a[MAX_N]; 25 int sa[MAX_N]; 26 int rk[MAX_N]; 27 int t1[MAX_N]; 28 int t2[MAX_N]; 29 int cnt[MAX_N]; 30 int tsa[MAX_N]; 31 int height[MAX_N]; 32 int par[MAX_N]; 33 long long siz[MAX_N]; 34 long long maxn[MAX_N]; 35 long long minn[MAX_N]; 36 long long v[MAX_N]; 37 long long ans[MAX_N]; 38 long long mul[MAX_N]; 39 char s[MAX_N]; 40 Height h[MAX_N]; 41 42 void rsort() 43 { 44 memset(cnt,0,sizeof(cnt)); 45 for(int i=1;i<=n;i++) cnt[t2[i]]++; 46 for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1]; 47 for(int i=n;i>=1;i--) tsa[cnt[t2[i]]--]=i; 48 memset(cnt,0,sizeof(cnt)); 49 for(int i=1;i<=n;i++) cnt[t1[i]]++; 50 for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1]; 51 for(int i=n;i>=1;i--) sa[cnt[t1[tsa[i]]]--]=tsa[i]; 52 } 53 54 void suffix() 55 { 56 memset(cnt,0,sizeof(cnt)); 57 for(int i=1;i<=n;i++) a[i]=s[i],cnt[a[i]]++; 58 for(int i=a;i<=z;i++) cnt[i]+=cnt[i-1]; 59 for(int i=1;i<=n;i++) rk[i]=cnt[a[i]]; 60 int len=1; 61 while(len<n) 62 { 63 for(int i=1;i<=n;i++) 64 { 65 t1[i]=rk[i]; 66 t2[i]=i+len<=n ? rk[i+len] : 0; 67 } 68 rsort(); 69 for(int i=1;i<=n;i++) 70 { 71 rk[sa[i]]=rk[sa[i-1]]+(t1[sa[i]]!=t1[sa[i-1]] || t2[sa[i]]!=t2[sa[i-1]]); 72 } 73 len<<=1; 74 } 75 int k=0; 76 for(int i=1;i<=n;i++) 77 { 78 k=k?k-1:k; 79 int j=sa[rk[i]-1]; 80 while(a[i+k]==a[j+k]) k++; 81 height[rk[i]]=k; 82 } 83 } 84 85 void init_union_find() 86 { 87 for(int i=1;i<=n;i++) 88 { 89 par[i]=i; 90 siz[i]=1; 91 maxn[i]=minn[i]=v[i]; 92 } 93 } 94 95 int find(int x) 96 { 97 return par[x]==x ? x : par[x]=find(par[x]); 98 } 99 100 void unite(int x,int y,int r) 101 { 102 int px=find(x); 103 int py=find(y); 104 ans[r]+=siz[px]*siz[py]; 105 mul[r]=max(mul[r],max(maxn[px]*maxn[py],minn[px]*minn[py])); 106 siz[py]+=siz[px]; 107 maxn[py]=max(maxn[py],maxn[px]); 108 minn[py]=min(minn[py],minn[px]); 109 par[px]=py; 110 } 111 112 void read() 113 { 114 scanf("%d%s",&n,s+1); 115 for(int i=1;i<=n;i++) scanf("%lld",&v[i]); 116 } 117 118 void work() 119 { 120 suffix(); 121 init_union_find(); 122 for(int i=2;i<=n;i++) h[i]=Height(height[i],i); 123 sort(h+2,h+1+n); 124 memset(ans,0,sizeof(ans)); 125 memset(mul,0x80,sizeof(mul)); 126 for(int i=n;i>=2;i--) unite(sa[h[i].id],sa[h[i].id-1],h[i].v); 127 for(int i=n-1;i>=0;i--) ans[i]+=ans[i+1],mul[i]=max(mul[i],mul[i+1]); 128 for(int i=0;i<n;i++) 129 { 130 if(ans[i]) printf("%lld %lld\n",ans[i],mul[i]); 131 else printf("0 0\n"); 132 } 133 } 134 135 int main() 136 { 137 read(); 138 work(); 139 }

BZOJ 4199 [Noi2015]品酒大會:後綴數組 + 並查集