首先如果没有出现次数的限制的话,这题就是超级钢琴
但由于有了这个限制,不能简单地用前缀和
考虑顺着做的时候每个点的贡献,如果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 ",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 ",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 ",q.top().v); 106 return 0; 107 }