BZOJ5249:[2018多省省隊聯測]IIIDX-線段樹

傳送門

題意:

你需要給給正在製作中的遊戲《IIIDX》安排曲目的解鎖順序。遊戲內共有n首曲目,每首曲目都會有一個難度d,遊戲內第i首曲目會在玩家Pass第ik 首曲目後解鎖。

安排這些曲目的順序,使得每次解鎖出的子的難度不低於作爲條件需要玩家通關的曲子的難度,即使得確定順序後的曲目的難度對於每個i滿足didik

輸出字典序最小的方案。

1n500000

Solution:

考場上一眼了一個做法:將權值從大到小排序,對於每個點貪心的放最大的符合條件的數,然後遞歸下去

但是這樣的做法只適合於d互不相同的情況,對於d相同的情況,有可能x及x的子樹並不需要填最大的值,和x同深度的x+1可能能填更大的數,舉個栗子:

10 2.0
1 2 2 2 2 2 3 4 5 6

正解非常神奇:從小到大排序後,線段樹維護ci 表示第i個不同的權值往右還能取的權值的個數(包括本身),然後我們從小到大枚舉每個點,對於每個點x,我們需要求一個最往右的位置pos滿足pos及pos左邊的所有cisize[x] (size[x] 爲以x爲根的子樹大小),求出pos之後修改一下c數組,表示預留出x子樹的點的位置,這些操作都可以通過線段樹來實現

需要注意的是:如果一個點有父親,那麼需要先把他父親爲子樹預留的東西去掉,而且每個父親預留的大小隻能去掉一次。

代碼:

#include<cstdio>
#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=500010;
int n,a[N],siz[N],x,ans[N],lsh[N],cnt;
int vis[N],fa[N];
bool tag[N];
vector<int> e[N];
struct tree{
    int l,r,v,tag;
}tr[4*N];
double k;
void update(int i)
{
    tr[i].v=min(tr[i<<1].v,tr[i<<1|1].v);
}
void build(int i,int l,int r)
{
    tr[i].l=l,tr[i].r=r;
    if (l==r) {tr[i].v=vis[l];return;}
    int mid=l+r>>1;
    build(i<<1,l,mid);build(i<<1|1,mid+1,r);
    update(i);
}
void dfs(int x)
{
    siz[x]=1;
    for (int i=0;i<(int)e[x].size();i++)
    {
        int y=e[x][i];fa[y]=x;
        dfs(y);
        siz[x]+=siz[y];
    }
}
void add(int i,int x)
{
    tr[i].v+=x;
    tr[i].tag+=x;
}
void pushdown(int i)
{
    if (tr[i].tag)
    {
        add(i<<1,tr[i].tag);add(i<<1|1,tr[i].tag);
        tr[i].tag=0;
    }
}
void modify(int i,int l,int r,int x)
{
    int L=tr[i].l,R=tr[i].r;
    if (L>r||l>R) return;
    if (l<=L&&R<=r) {add(i,x);return;}
    pushdown(i);
    modify(i<<1,l,r,x);modify(i<<1|1,l,r,x);
    update(i);
}
int query(int i,int pos)
{
    int L=tr[i].l,R=tr[i].r;
    if (L==R) return (tr[i].v>=pos)?L:L-1;
    pushdown(i);
    if (tr[i<<1].v>=pos) return query(i<<1|1,pos);else return query(i<<1,pos);
}
//void pr(int i)
//{
//  if (tr[i].l==tr[i].r) {printf("%d ",tr[i].v);return;}
//  pushdown(i);
//  pr(i<<1);pr(i<<1|1);
//}
int main()
{
//  freopen("iiidx.in","r",stdin);
//  freopen("iiidx.out","w",stdout);
    scanf("%d%lf",&n,&k);for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+1+n);for (int i=1;i<=n;i++) lsh[++cnt]=a[i];
    cnt=unique(lsh+1,lsh+1+cnt)-lsh-1;for (int x,i=1;i<=n;i++) x=lower_bound(lsh+1,lsh+1+cnt,a[i])-lsh,vis[x]++;
    for (int i=cnt;i>=1;i--) vis[i]+=vis[i+1];
    build(1,1,cnt);

    for (int i=1;i<=n;i++)
    {
        int y=(1.0*i/k+1e-8);
        e[y].push_back(i);
    }
    dfs(0);tag[0]=1;
    for (int i=1;i<=n;i++)
    {
        if (!tag[fa[i]]) tag[fa[i]]=1,modify(1,1,ans[fa[i]],siz[fa[i]]-1);
    //  cout<<i<<endl;
    //  pr(1);cout<<endl;
        ans[i]=query(1,siz[i]);
        modify(1,1,ans[i],-siz[i]);
    //  pr(1);cout<<endl;
    }
    for (int i=1;i<=n;i++) printf("%d ",lsh[ans[i]]);
}
發佈了115 篇原創文章 · 獲贊 15 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章