• 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
    ",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 }
  • 相关阅读:
    剑指offer55. 平衡二叉树
    剑指offer52. 两个链表的第一个公共节点
    LC1043. Partition Array for Maximum Sum
    剑指offer40. Top K
    剑指offer39. 数组中出现次数超过一半的数字
    剑指offer36.将BST原地转换为双向循环链表
    判断大小端
    CentOS安装RabbitMQ 3.8.9
    Nginx 413 Request Too Large 错误
    NginxPC端和移动端区分
  • 原文地址:https://www.cnblogs.com/Ressed/p/9794770.html
Copyright © 2020-2023  润新知