#2472. 「九省联考 2018」IIIDX

一眼思路的题…
就是比较难写..
考虑一个点必须小于其 idk ⌊ i d k ⌋ 那么容易想出一个树形结构,每个点都大于其父亲.
那么对于一个点,那么他能选取的最大值就是当前能选的所有点中的 nsize[id] n − s i z e [ i d ] 这个点的值。
然后留够其儿子的位置即可。
最后如果有相同的点,容易想到把当前点放在权值相同的最前面处

c++代码如下:

#include<bits/stdc++.h>
#define lowbit(x) (x & - x)
#define rep(i,x,y) for(register int i = x ; i <= y; ++ i)
#define repd(i,x,y) for(register int i = x ; i >= y; -- i)
using namespace std;
typedef long long ll;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
template<typename T>inline void read(T&x)
{
    x = 0;char c;int sign = 1;
    do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
    do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
    x *= sign;
}
const int N = 1e6 + 500;
double k; int n,d[N],f[N],size[N];
int head[N],nxt[N << 1],to[N << 1],tot;
inline void add(int x,int y)
{
    to[tot] = y;
    nxt[tot] = head[x];
    head[x] = tot++;
}

struct Seg
{
    int lzy[N << 2],lzy2[N << 2],val[N<< 2],mx[N << 2],mi[N << 2];

    void build(int id,int l,int r)
    {
        val[id] = r - l + 1; mx[id] = r;
        if(l == r) return;
        int mid = l + r >> 1;
        build(id<<1,l,mid);
        build(id<<1|1,mid+1,r);
    }

    inline void put_down(int id)
    {
        if(!lzy[id]) return;
        mx[id<<1] += lzy[id];
        mx[id<<1|1] += lzy[id];
        mi[id<<1] += lzy[id];
        mi[id<<1|1] += lzy[id];
        lzy[id << 1] += lzy[id];
        lzy[id << 1|1] += lzy[id];
        lzy[id] = 0;
    }

    int m;
    int Query(int id,int l,int r,int w)
    {
        if (l == r) return l;
        int mid = l + r >> 1;
        put_down(id);

        int x = val[id<<1|1] - max((max(mx[id<<1],m)- mi[id << 1|1] - mid -1),0);

        if(x >= w){
            m = max(mx[id<<1],m);
            return Query(id<<1|1,mid+1,r,w);
         }
        else
        {
            w -= val[id<<1|1];
            return Query(id<<1,l,mid,w);
         }
    }

    void update(int id,int l,int r,int L,int R,int w)
    {
        if(l == L && r == R)
        {
            mi[id] += w;
            mx[id] += w;
            lzy[id] += w;
            return;
        }
        int mid = l + r >> 1;
        put_down(id);
        if(L > mid)update(id<<1|1,mid+1,r,L,R,w);
        else if(R <= mid)update(id<<1,l,mid,L,R,w);
        else update(id<<1,l,mid,L,mid,w) , update(id<<1|1,mid+1,r,mid+1,R,w);
        mx[id] = max(mx[id<<1],mx[id<<1|1]);
        mi[id] = max(mi[id<<1],mi[id<<1|1]);
    }

    void modify(int id,int l,int r,int pos,int w)
    {
        val[id] += w;
        if(l == r) return;
        int mid = l + r >> 1;
        put_down(id);
        if( pos <= mid) modify(id<<1,l,mid,pos,w);
        else modify(id<<1|1,mid+1,r,pos,w);
    }

}seg;

void dfs(int x)
{
    size[x] = 1;
    for(register int i = head[x];~i;i=nxt[i])
        if(to[i] != f[x])
        {
            f[to[i]] = x;
            dfs(to[i]);
            size[x] += size[to[i]];
        }
}

int ans[N],p[N],id[N];

int get_fa(int x) { return p[x] == x ? x : p[x] = get_fa(p[x]); }

bool vis[N];

int main()
{
    memset(head,-1,sizeof head);
    read(n); cin>>k;
    rep(i,1,n) read(d[i]);

    rep(i,1,n) if((int)(i/k) >= 1) add((int)(i/k),i);

    sort(d + 1,d + 1 + n);

    rep(i,1,n) p[i] = i;
    rep(i,1,n) if(d[i] != d[i-1]) id[i] = i;else id[i] = id[i-1];

    seg.build(1,1,n);

    rep(i,1,n) if(!size[i]) dfs(i);
    rep(x,1,n)
    {
        if(f[x]) seg.update(1,1,n,1,ans[f[x]],-size[f[x]]);
        if(f[x]) seg.modify(1,1,n,ans[f[x]],size[f[x]]);

        seg.m = 0;
        ans[x] = seg.Query(1,1,n,size[x]);
        ans[x] = id[ans[x]];
        ans[x] = get_fa(id[ans[x]]);
        p[ans[x]] = ans[x] + 1;

        if(f[x]) size[f[x]] -= size[x];
        if(f[x]) seg.update(1,1,n,1,ans[f[x]],size[f[x]]);
        if(f[x]) seg.modify(1,1,n,ans[f[x]],-size[f[x]]);
        seg.update(1,1,n,1,ans[x],size[x]);
        seg.modify(1,1,n,ans[x],-size[x]);
    }

    rep(i,1,n) printf("%d ",d[ans[i]]);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值