bzoj4504 K个串 (优先队列+主席树)

首先如果没有出现次数的限制的话,这题就是超级钢琴

但由于有了这个限制,不能简单地用前缀和

考虑顺着做的时候每个点的贡献,如果a[i]=x,x上次出现位置是lst[x](可以用一个map来记),那它会给右端点为[i,N],左端点为[lst[x]+1,i]的区间带来x的贡献

根据szr巨佬的说法,主席树的本质就是前缀和套线段树,所以我们如果按区间的右端点建主席树的根,每颗线段树内部存每个位置作为左端点的最大值,只需要给root[i]这棵树上[lst[x]+1,i]做区间+=x就可以了

而且i后面的位置的树还没有建出来,所以不用担心修改以后的更新问题

那么主席树上怎么区间修改呢...对于这道题,只需要像正常的线段树一样pushdown,update,但是每次修改子节点的时候都是新开一个点,然后把信息拷贝过去再修改,在连过去,防止改到前面线段树上的值

然后开优先队列,记下来(x,v,l,r,m)表示右端点为x,在[l,r]的范围内最大值是v,在m取到,每次取出来队顶,然后分割成(x,v',l,m-1,m')和(x,v",m+1,r,m")再塞回队列里,这样做K-1次,最后的队顶就是答案

时空复杂度大概都是$O(nlogn)$的,空间要开大一点。

  1 #include<bits/stdc++.h>
  2 #define pa pair<ll,int>
  3 #define CLR(a,x) memset(a,x,sizeof(a))
  4 using namespace std;
  5 typedef long long ll;
  6 const int maxn=1e5+10,maxp=maxn*100;
  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 struct Node{
 17     int x,l,r,m;ll v;
 18     Node(ll a=0,int b=0,int c=0,int d=0,int e=0){
 19         v=a,x=b,l=c,r=d,m=e;
 20     }
 21 };
 22 bool operator < (Node a,Node b){return a.v<b.v;}
 23 
 24 ll laz[maxp];int ch[maxp][2],root[maxn],pct;
 25 pa v[maxp];
 26 int N,K;
 27 map<int,int> lst;
 28 priority_queue<Node> q;
 29 
 30 inline void update(int p){
 31     v[p]=max(v[ch[p][0]],v[ch[p][1]]);
 32 }
 33 inline int add(int p,ll y){
 34     v[++pct]=v[p];
 35     ch[pct][0]=ch[p][0],ch[pct][1]=ch[p][1];
 36     laz[pct]=laz[p]+y;
 37     v[pct].first+=y;
 38     return pct;
 39 }
 40 inline void pushdown(int p){
 41     if(!laz[p]) return;
 42     ch[p][0]=add(ch[p][0],laz[p]);
 43     ch[p][1]=add(ch[p][1],laz[p]);
 44     laz[p]=0;
 45 }
 46 
 47 void build(int &p,int l,int r){
 48     p=++pct;
 49     if(l==r) v[p]=make_pair(0,l);
 50     else{
 51         int m=l+r>>1;
 52         build(ch[p][0],l,m);
 53         build(ch[p][1],m+1,r);
 54         update(p);
 55     }
 56 }
 57 
 58 void insert(int &p,int pre,int l,int r,int x,int y,int z){
 59     if(x<=l&&r<=y){
 60         p=add(pre,z);
 61     }else{
 62         pushdown(p);
 63         int m=l+r>>1;p=++pct;
 64         ch[p][0]=ch[pre][0],ch[p][1]=ch[pre][1];
 65         if(x<=m) insert(ch[p][0],ch[pre][0],l,m,x,y,z);
 66         if(y>=m+1) insert(ch[p][1],ch[pre][1],m+1,r,x,y,z);
 67         update(p);
 68     }
 69 }
 70 
 71 pa query(int p,int l,int r,int x,int y){
 72     pushdown(p);
 73     // printf("%d %d %d %d\n",l,r,x,y);
 74     if(x<=l&&r<=y) return v[p];
 75     else{
 76         int m=l+r>>1;pa re=make_pair(-inf,-1);
 77         if(x<=m) re=query(ch[p][0],l,m,x,y);
 78         if(y>=m+1) re=max(re,query(ch[p][1],m+1,r,x,y));
 79         return re;
 80     }
 81 }
 82 
 83 int main(){
 84     //freopen("","r",stdin);
 85     int i,j,k;
 86     N=rd(),K=rd();
 87     build(root[0],1,N);
 88     for(i=1;i<=N;i++){
 89         int x=rd();
 90         insert(root[i],root[i-1],1,N,lst[x]+1,i,x);
 91         // printf("mm");
 92         lst[x]=i;
 93         pa re=query(root[i],1,N,1,i);
 94         // printf("%d %d %d\n",i,re.first,re.second);
 95         q.push(Node(re.first,i,1,i,re.second));
 96     }
 97     for(i=1;i<K;i++){
 98         Node p=q.top();q.pop();
 99         pa rl,rr;
100         // pa rl=query(root[p.x],1,N,p.l,p.m-1);
101         // pa rr=query(root[p.x],1,N,p.m+1,p.r);
102         if(p.l<p.m) rl=query(root[p.x],1,N,p.l,p.m-1),q.push(Node(rl.first,p.x,p.l,p.m-1,rl.second));
103         if(p.m<p.r) rr=query(root[p.x],1,N,p.m+1,p.r),q.push(Node(rr.first,p.x,p.m+1,p.r,rr.second));
104     }
105     printf("%lld\n",q.top().v);
106     return 0;
107 }

 

posted @ 2018-10-15 21:17  Ressed  阅读(133)  评论(0编辑  收藏  举报