• [九省联考2018]IIIDX


    传送门
    形式化题意:一棵树,对于每个节点赋予一个给定的权值,使得每个节点都不大于子树内节点,同时满足编号小的点尽可能大。
    首先在所有给定的数不同的时候只要贪心一次,从小到大把数排序,之后建树在上面跑dfs,按dfn从小到大给权值。
    但是这样在有相同的数据的时候是会错的。因为有可能通过交换使得子树内节点权值和根相等。(例子在luogu讨论区有的)
    我们重新考虑一下。把所有的数从大到小排序,记录(C_i)为每个点左边还能被使用的权值个数。这样的话每次找一个位置赋权值的话,其实就是找一个位置使得它右边所有位置的(C_i)不大于子树大小。这个可以在线段树上二分。
    不过二分出来的不一定是最好的答案,因为有重复的数字所以你取最优的结果一定是在最右侧,需要额外维护一下应该调到的位置。
    然后每次更新后需要在修改位置的右边全部减去子树大小。注意,每次遍历完一个父亲的时候要加上他的子树大小。相当于把原来预留的空间放了出来。
    然后就完事了……代码不长……

    #include<bits/stdc++.h>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define pr pair<int,int>
    #define mp make_pair
    #define fi first
    #define sc second
    using namespace std;
    typedef long long ll;
    const int M = 1000005;
    const int N = 10000005;
     
    int read()
    {
       int ans = 0,op = 1;char ch = getchar();
       while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
       while(ch >='0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
       return ans * op;
    }
    
    struct tree
    {
       int minn,lazy;
    }t[M<<2];
    bool cmp(int x,int y){return x > y;}
    int n,a[M],b[M],cur = 1,dfn[M],idx,fa[M],size[M],ans[M],cnt[M];
    double k;
    
    void pushdown(int p)
    {
       t[p<<1].lazy += t[p].lazy,t[p<<1|1].lazy += t[p].lazy;
       t[p<<1].minn += t[p].lazy,t[p<<1|1].minn += t[p].lazy;
       t[p].lazy = 0;
    }
    
    void build(int p,int l,int r)
    {
       if(l == r) {t[p].minn = l;return;}
       int mid = (l+r) >> 1;
       build(p<<1,l,mid),build(p<<1|1,mid+1,r);
       t[p].minn = min(t[p<<1].minn,t[p<<1|1].minn);
    }
    
    int query(int p,int l,int r,int k)
    {
       if(l == r){return t[p].minn >= k ? l : l + 1;}
       pushdown(p);
       int mid = (l+r) >> 1;
       if(k <= t[p<<1|1].minn) return query(p<<1,l,mid,k);
       else return query(p<<1|1,mid+1,r,k);
    }
    
    void update(int p,int l,int r,int kl,int kr,int val)
    {
       if(l == kl && r == kr) {t[p].minn += val,t[p].lazy += val;return;}
       pushdown(p);
       int mid = (l+r) >> 1;
       if(kr <= mid) update(p<<1,l,mid,kl,kr,val);
       else if(kl > mid) update(p<<1|1,mid+1,r,kl,kr,val);
       else update(p<<1,l,mid,kl,mid,val),update(p<<1|1,mid+1,r,mid+1,kr,val);
       t[p].minn = min(t[p<<1].minn,t[p<<1|1].minn);
    }
    
    int main()
    {
       n = read(),scanf("%lf",&k);
       rep(i,1,n) a[i] = read();
       sort(a+1,a+1+n,cmp);
       per(i,n-1,1) cnt[i] = (a[i] == a[i+1]) ? cnt[i+1] + 1 : 0;
       rep(i,1,n) fa[i] = (int)floor(i/k),size[i] = 1;
       per(i,n,1) size[fa[i]] += size[i];
       build(1,1,n);
       rep(i,1,n)
       {
          if(fa[i] && fa[i] != fa[i-1]) update(1,1,n,ans[fa[i]],n,size[fa[i]]-1);
          int cur = query(1,1,n,size[i]);
          cur += cnt[cur],cnt[cur]++,ans[i] = cur;
          update(1,1,n,cur,n,-size[i]);
       }
       rep(i,1,n) printf("%d ",a[ans[i]]);enter;
       return 0;
    }
    
  • 相关阅读:
    dhl:有用的sql语句(我用到的)更新中....
    dhl:给Button设背景图片
    遍历一个类中的每一个属性、方法、公共字段
    swf、wmv、mov、RM几种常见格式视频播放器代码!
    理解Windows中的路由表和默认网关
    主/辅DNS服务器详细配置
    用组策略彻底禁止USB存储设备、光驱、软驱、ZIP软驱
    DHCP中继原理及配置--路由器
    路由器NAT功能配置简介
    网络负载平衡群集
  • 原文地址:https://www.cnblogs.com/captain1/p/10508179.html
Copyright © 2020-2023  润新知