1. 程式人生 > >luogu2178/bzoj4199 品酒大會 (SA+單調棧)

luogu2178/bzoj4199 品酒大會 (SA+單調棧)

int 單調棧 bit targe through ref http def get

他要求的就是lcp(x,y)>=i的(x,y)的個數和a[x]*a[y]的最大值

做一下後綴和,就只要求lcp=i的了

既然lcp(x,y)=min(h[rank[x]+1],..,[h[rank[y]]])

那麽我們求出來對於每一個h,以它作為最小值的區間的左右端點就可以了,這個可以用單調棧,具體做法見Neat Tree(?哪裏具體了)

假設L是i左面第一個h小於等於它的,R是i右面第一個小於它的(一定要一邊有=一邊沒有,很關鍵)

那就相當於lcp(x,y)=h[i] ,rank[x]∈[L,i-1],rank[y]∈[i,R-1]

數量就是這兩個區間大小乘一下,最大值是max(最大值之積,最小值之積)(因為會有負的),這個可以用ST表來做

貌似並查集也能做 但我哪會啊

寫的這麽辣雞 開著O2才勉強水過洛谷 哪敢到bzoj去交啊

upd:技術分享圖片(Time Limit: 10 Sec)

  1 #include<bits/stdc++.h>
  2 #define pa pair<ll,ll>
  3 #define CLR(a,x) memset(a,x,sizeof(a))
  4 using namespace std;
  5 typedef long long ll;
  6 const int maxn=3e5+10;
  7 const ll inf=1e18;
  8 
  9
inline ll rd(){ 10 ll x=0;char c=getchar();int neg=1; 11 while(c<0||c>9){if(c==-) neg=-1;c=getchar();} 12 while(c>=0&&c<=9) x=x*10+c-0,c=getchar(); 13 return x*neg; 14 } 15 16 int N,M,deli[maxn],sa[maxn<<1],rnk[maxn<<1],rnk1[maxn<<1
],tmp[maxn<<1],h[maxn<<1],cnt[maxn]; 17 ll ans2[maxn],ma[maxn][20],mn[maxn][20],dt[maxn]; 18 int stk[maxn],sh,rg[maxn]; 19 char s[maxn]; 20 21 inline void setsa(){ 22 int i,j=0,k; 23 for(i=1;i<=N;i++) cnt[s[i]]=1; 24 for(i=1;i<=M;i++) cnt[i]+=cnt[i-1]; 25 for(i=N;i;i--) rnk[i]=cnt[s[i]]; 26 for(k=1;j!=N;k<<=1){ 27 // printf("%d %d %d\n",M,k,j); 28 CLR(cnt,0); 29 for(i=1;i<=N;i++) cnt[rnk[i+k]]++; 30 for(i=1;i<=M;i++) cnt[i]+=cnt[i-1]; 31 for(i=N;i;i--) tmp[cnt[rnk[i+k]]--]=i; 32 CLR(cnt,0); 33 for(i=1;i<=N;i++) cnt[rnk[i]]++; 34 for(i=1;i<=M;i++) cnt[i]+=cnt[i-1]; 35 for(i=N;i;i--) sa[cnt[rnk[tmp[i]]]--]=tmp[i]; 36 memcpy(rnk1,rnk,sizeof(rnk)); 37 i=2;rnk[sa[1]]=j=1; 38 for(;i<=N;i++){ 39 if(rnk1[sa[i]]!=rnk1[sa[i-1]]||rnk1[sa[i]+k]!=rnk1[sa[i-1]+k]) j++; 40 rnk[sa[i]]=j; 41 }M=j; 42 } 43 for(i=1;i<=N;i++) 44 sa[rnk[i]]=i; 45 } 46 inline void seth(){ 47 for(int i=1,j=0;i<=N;i++){ 48 if(rnk[i]==1) continue; 49 if(j) j--; 50 int x=sa[rnk[i]-1]; 51 while(i+j<=N&&x+j<=N&&s[i+j]==s[x+j]) j++; 52 h[rnk[i]]=j; 53 } 54 } 55 56 inline void setma(){ 57 for(int i=N;i;i--){ 58 ma[i][0]=mn[i][0]=deli[sa[i]]; 59 for(int j=1;i+(1<<j)-1<=N;j++){ 60 int k=i+(1<<(j-1)); 61 ma[i][j]=max(ma[i][j-1],ma[k][j-1]); 62 mn[i][j]=min(mn[i][j-1],mn[k][j-1]); 63 } 64 } 65 } 66 67 inline pa getma(int l,int r){ 68 int k=log2(r-l+1); 69 return make_pair(max(ma[l][k],ma[r-(1<<k)+1][k]),min(mn[l][k],mn[r-(1<<k)+1][k])); 70 } 71 72 void solve(){ 73 for(int i=2;i<=N;i++){ 74 while(sh&&h[stk[sh]]>h[i]) 75 rg[stk[sh--]]=i; 76 stk[++sh]=i; 77 }while(sh) rg[stk[sh--]]=N+1; 78 for(int i=N;i;i--){ 79 while(sh&&h[stk[sh]]>=h[i]){ 80 int r=rg[stk[sh]]-1; 81 pa x=getma(i,stk[sh]-1),y=getma(stk[sh],r); 82 ans2[h[stk[sh]]]=max(ans2[h[stk[sh]]],max(x.first*y.first,x.second*y.second)); 83 dt[h[stk[sh]]]+=1ll*(stk[sh]-i)*(r-stk[sh]+1); 84 sh--; 85 } 86 stk[++sh]=i; 87 } 88 } 89 90 int main(){ 91 // freopen("testdata.in","r",stdin); 92 // freopen("aa.out","w",stdout); 93 int i,j,k; 94 N=rd(); 95 scanf("%s",s+1); 96 for(i=1;i<=N;i++) 97 deli[i]=rd(); 98 M=127;setsa(); 99 seth(); 100 setma(); 101 CLR(ans2,-127); 102 solve(); 103 for(i=N-1;i>=0;i--) dt[i]+=dt[i+1],ans2[i]=max(ans2[i],ans2[i+1]); 104 for(i=0;i<N;i++) 105 printf("%lld %lld\n",dt[i],dt[i]?ans2[i]:0); 106 return 0; 107 }

luogu2178/bzoj4199 品酒大會 (SA+單調棧)