NOI2015品酒大会 后缀数组

自己尝试敲后缀数组,发现难看(tiao)的不行,于是抄了板子

考虑建出hei以后转化出的问题:

对于一个数组中权值大于等于k的连续部分,求取两个数的方案数和两数积的最大值

(好气啊,可以有负数)

把询问倒序以后相当于连续部分之间会动态加元素,使他们连起来

维护一段极大连续段的最大值、最小值、长度,保存在左右两端——wtf我也不知道这算什么做法

然后瞎**乱搞一下,就能每次合并O(1)维护出来了(似乎没比并查集好多少)

  1 #include <bits/stdc++.h>
  2 #define N 300001
  3 #define MIN -9223372036854775807
  4 #define calc(x) (x)*((x)-1)/2
  5 #define ll long long
  6 using namespace std;
  7 ll n,ans,ans2;
  8 ll c[N],mi[N],ma[N],len[N],w[N]; 
  9 ll sa[N],Rank[N],height[N];
 10 ll wa[N],wb[N],wv[N],wd[N];
 11 ll out1[N],out2[N];
 12 struct node
 13 {
 14     ll x,y;
 15     node(ll p,ll q)
 16     {
 17         x=p;y=q;
 18     }
 19     node()
 20     {
 21     }
 22 } t[N];
 23 bool cmp(ll *r,ll a,ll b,ll l)
 24 {
 25     return r[a]==r[b]&&r[a+l]==r[b+l];
 26 }
 27 bool com(node a,node b)
 28 {
 29     return a.x>b.x;
 30 }
 31 void da(ll *r,ll n,ll m)
 32 {
 33     ll *x=wa,*y=wb,*t;
 34     for (ll i=0;i<m;i++) wd[i]=0;
 35     for (ll i=0;i<n;i++) wd[x[i]=r[i]]++;
 36     for (ll i=1;i<m;i++) wd[i]+=wd[i-1];
 37     for (ll i=n-1;i>=0;i--) sa[--wd[x[i]]]=i;
 38     for (ll j=1,p=1,i;p<n;j<<=1,m=p)
 39     {
 40         for (p=0,i=n-j;i<n;i++) y[p++]=i;
 41         for (i=0;i<n;i++) if (sa[i]>=j) y[p++]=sa[i]-j;
 42         for (i=0;i<n;i++) wv[i]=x[y[i]];
 43         for (i=0;i<m;i++) wd[i]=0;
 44         for (i=0;i<n;i++) wd[wv[i]]++;
 45         for (i=1;i<m;i++) wd[i]+=wd[i-1];
 46         for (i=n-1;i>=0;i--) sa[--wd[wv[i]]]=y[i];
 47         for (t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
 48             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
 49     }
 50 }
 51 void get_height(ll *r,ll n)
 52 {
 53     for (ll i=1;i<=n;i++) Rank[sa[i]]=i;
 54         for (ll i=0,k=0,j;i<n;height[Rank[i++]]=k)
 55             for (k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);
 56 }
 57 void merge(ll x,ll y)
 58 {
 59     if(!len[x] || !len[y]) return;
 60     ans2+=calc(len[x]+len[y]+1)-calc(len[x]+1)-calc(len[y]+1);
 61     ans=max(ans,w[sa[x-len[x]]]*mi[y]);ans=max(ans,mi[x]*mi[y]);
 62     ans=max(ans,w[sa[x-len[x]]]*ma[y]);ans=max(ans,ma[x]*ma[y]);
 63     ll MI=min(mi[x],mi[y]),MA=max(ma[x],ma[y]);
 64     mi[x-len[x]+1]=mi[y+len[y]-1]=MI;
 65     ma[x-len[x]+1]=ma[y+len[y]-1]=MA;
 66     len[x-len[x]+1]=len[y+len[y]-1]=len[x]+len[y];
 67 }
 68 void add(ll now)
 69 {
 70     if(!now) return;
 71     len[now]=1;
 72     mi[now]=ma[now]=w[sa[now]];
 73     ans=max(ans,w[sa[now]]*w[sa[now-1]]);
 74     ++ans2;
 75     if(now)
 76         merge(now-1,now);
 77     if(now<n-1)
 78         merge(now,now+1);
 79 }
 80 int main()
 81 {
 82     scanf("%lld",&n);
 83     for(ll i=0;i<n;i++)
 84     {
 85         char ch;
 86         while(ch=getchar(),!isalpha(ch));
 87         c[i]=ch-'a'+1;
 88     }
 89     for(ll i=0;i<n;i++)
 90         scanf("%lld",&w[i]);
 91     c[n]=0;
 92     da(c,n+1,27);
 93     get_height(c,n);
 94     for(ll i=0;i<n;i++)
 95         sa[i]=sa[i+1],height[i]=height[i+1];
 96     if(0)
 97     for(ll i=0;i<n;i++)
 98     {
 99         printf("%lld %lld\n",sa[i],height[i]);
100     }
101     for(ll i=0;i<n;i++)
102         t[i]=node(height[i],i);
103     sort(t,t+n,com);
104     ll j=0;
105     ans=MIN;ans2=0;
106     for(ll i=0;i<n;i++)
107         len[i]=0,ma[i]=MIN,mi[i]=-MIN;
108     for(ll i=n-1;i>=0;i--)
109     {
110         while(j<n && t[j].x==i) add(t[j].y),j++;
111         out1[i]=ans2;out2[i]=(ans==MIN)?0:ans;
112     }
113     for(ll i=0;i<n;i++)
114         printf("%lld %lld\n",out1[i],out2[i]);
115     return 0;
116 }

 

posted @ 2017-05-12 12:58  汪立超  阅读(180)  评论(0编辑  收藏  举报