zoukankan      html  css  js  c++  java
  • [九省联考2018]iiidx (线段树+贪心)

    题目大意:给你一个序列,让你对它重新排列,保证a[i]<=a[i/k],求字典序最大的排列

    洛谷传送门​​​​​​​

    把i/k和i连边,发现形成了一个类似于小根堆的树形结构

    先是一个错误的贪心:贪心每次选择前size[x]大个数依次填到树里

    这种方法在有重复数字的时候会出锅,比如1112,如果用上面的方法就是1112,但正确的是1121

    原因呢,就是填满一颗子树内并不一定要用完偏大的,可能和子树根同一深度的另一个节点可以取到更大的,比如有很多1,很少的2,我可能只要一些1就能把这棵子树填满,然后留给一些2给后面的子树去填。

    然后我想了一个splay维护的贪心,就是相同的只取能填满子树且偏小的,但被我自己hack掉了,因为后面的子树不一定用光大的,可以把大的留给前面的来保证字典序最大

    所以题解的方法还是很神的,用线段树来维护这个贪心

    建一颗维护最小值和区间修改的线段树,维护一个变量F[i]表示 i 之前还有多少个节点可用

    每次预留出size[x]个,在线段树上二分找到一个最小位置 i 满足F[k]>=size[x](k=i...n),那么这个点的答案就是a[i],如果有多个相同的,就找最后一个,可以预处理一个Last来解决,如果取过了某个节点就lasta[a[i]]--(因为所有相同的a[i]是等价的所以不用考虑位置),a[i]比较大需要离散。然后区间修改i...n全部减掉size[x]

    然后遍历到子节点时,如果父节点的预留没有被加回来,就把父节点预留的部分重新加回来size[fa]-1个(父节点自己要占一个)

    其实这可以看成对树进行BFS的过程,要保证同一深度的节点都能取到最大值,所以有了“预留”这种操作来防止不同子树间的冲突

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #define il inline
      5 #define dd double
      6 #define N 501000
      7 using namespace std;
      8 //re
      9 int n,cte,cnt;dd K;
     10 int a[N],org[N],lst[N],sz[N],head[N],ans[N],fa[N],add[N],id[N];
     11 struct node{int id,val;}b[N];
     12 struct Edge{int to,nxt;}edge[N];
     13 void ae(int u,int v){
     14     cte++;edge[cte].to=v;
     15     edge[cte].nxt=head[u],head[u]=cte;
     16 }
     17 int cmp(int x,int y){return x>y;}
     18 int cmp1(node x,node y){return x.val<y.val;}
     19 int cmp2(node x,node y){return x.id<y.id;}
     20 struct Seg{
     21     int mi[N<<2],tag[N<<2];
     22     il void pushup(int rt){mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);}
     23     il void pushdown(int rt)
     24     {
     25         if(!tag[rt]) return;
     26         tag[rt<<1]+=tag[rt],tag[rt<<1|1]+=tag[rt];
     27         mi[rt<<1]+=tag[rt],mi[rt<<1|1]+=tag[rt];
     28         tag[rt]=0;
     29     }
     30     void build(int l,int r,int rt)
     31     {
     32         if(l==r){mi[rt]=l;return;}
     33         int mid=(l+r)>>1;
     34         build(l,mid,rt<<1);
     35         build(mid+1,r,rt<<1|1);
     36         pushup(rt);
     37     }
     38     void update(int L,int R,int l,int r,int rt,int w)
     39     {
     40         if(L<=l&&r<=R){mi[rt]+=w,tag[rt]+=w;return;}
     41         int mid=(l+r)>>1;
     42         pushdown(rt);
     43         if(L<=mid) update(L,R,l,mid,rt<<1,w);
     44         if(R>mid) update(L,R,mid+1,r,rt<<1|1,w);
     45         pushup(rt);
     46     }
     47     int find(int w,int l,int r,int rt)
     48     {
     49         if(l==r) return mi[rt]>=w?l:l+1;
     50         int mid=(l+r)>>1;
     51         pushdown(rt);
     52         if(mi[rt<<1|1]>=w) return find(w,l,mid,rt<<1);
     53         else return find(w,mid+1,r,rt<<1|1);
     54         pushup(rt);
     55     }
     56 }seg;
     57 int gint()
     58 {
     59     int ret=0,fh=1;char c=getchar();
     60     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
     61     while(c>='0'&&c<='9'){ret=(ret<<3)+(ret<<1)+c-'0';c=getchar();}
     62     return ret*fh;
     63 }
     64 void dfs1(int u)
     65 {
     66     for(int j=head[u];j;j=edge[j].nxt){
     67         int v=edge[j].to;
     68         dfs1(v);sz[u]+=sz[v];
     69     }sz[u]++;
     70 }
     71 void descrete()
     72 {
     73     sort(b+1,b+n+1,cmp1);
     74     for(int i=1;i<=n;i++){
     75         if(b[i].val!=b[i-1].val)
     76             org[++cnt]=b[i].val;
     77         a[i]=cnt;
     78     }
     79 }
     80 void solve()
     81 {
     82     for(int i=1;i<=n;i++)
     83     {
     84         if(fa[i]&&!add[fa[i]]) 
     85             seg.update(id[fa[i]],n,1,n,1,sz[fa[i]]-1),add[fa[i]]=1;
     86         int x=seg.find(sz[i],1,n,1);
     87         ans[i]=a[x],id[i]=x;
     88         seg.update(lst[ans[i]],n,1,n,1,-sz[i]);
     89         lst[ans[i]]--;
     90     }
     91 }
     92 
     93 int main()
     94 {
     95     scanf("%d%lf",&n,&K);
     96     for(int i=1;i<=n;i++)
     97         b[i].val=gint(),b[i].id=i;
     98     descrete();
     99     sort(a+1,a+n+1,cmp);
    100     for(int i=1;i<=n;i++)
    101         lst[a[i]]=i;
    102     for(int i=n;i>=1;i--)
    103         fa[i]=(int)(1.0*i/K),ae(fa[i],i);
    104     dfs1(0);
    105     seg.build(1,n,1);
    106     solve();
    107     for(int i=1;i<=n;i++)
    108         printf("%d ",org[ans[i]]);
    109     puts("");
    110     return 0;
    111 }
  • 相关阅读:
    Hadoop命令大全
    Cube中时间维度
    无法锁定管理目录(/var/lib/dpkg/),是否有其他进程正占用它?
    IE6、IE7、IE8、FF对空标签块状元素解释的不同点
    SSIS导出平面文件数据带_x003C_none_x003E的问题
    用DB2 Runtime Client实现Apache Derby 数据库ODBC编程
    区块链技术探索
    JS原型对象
    this关键字
    消息认证码
  • 原文地址:https://www.cnblogs.com/guapisolo/p/9760688.html
Copyright © 2011-2022 走看看