Codeforces 1154E - Two Teams - [線段樹+鏈表]

題目連接:https://codeforces.com/contest/1154/problem/Ec++

 

題意:ui

$n$ 我的排成一排,第 $i$ 我的的能力值爲 $a[i]$,$a[1 \sim n]$ 是 $1 \sim n$ 的某個排列。spa

第一個教練先來拉人,他會拉目前還在隊伍中的 $a[i]$ 最高的那我的,而且把排在它前面和後面的各自 $k$ 我的都拉走,即最多能夠拉走 $2k + 1$ 我的。指針

而後,第二個教練來拉人,也是一樣的操做。注意,若是當前被拉走的人的前面或者後面不足 $k$ 我的,那就儘量多地拉人。code

兩個教練輪流拉人,直到整個隊伍中一我的都不剩。要求你給出最後每一個人被哪一個教練拉走了。blog

 

題解:ci

老年手速選手,時間緊沒寫完……get

一開始先考慮直接用一個線段樹搞定,發現有點難……並且時間複雜度也不必定能過。it

後來,考慮加入一個鏈表來維護目前的這一排隊伍。class

咱們用線段樹維護這 $n$ 我的的能力值;能夠作到對整個區間求最大值,也就能知道目前隊伍裏哪一個人是能力值最大的;其次用線段樹作區間修改,能夠把被拉走的人的能力值設爲 $0$。

而後,對於被拉走的那我的,咱們在鏈表上分別往前、日後移動指針 $k$ 次,就能獲得須要刪去的那一段鏈,直接 $O(1)$ 刪除。同時在指針移動時順便把每一個人標記好他們是被哪一個教練拉走的。

這樣一來,時間複雜度爲 $O(\frac{n}{k} \log n + n)$。

 

AC代碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;

int n,k,a[maxn];
int pos[maxn];
int head,tail,pre[maxn],nxt[maxn];
int ans[maxn];

#define ls (rt<<1)
#define rs (rt<<1|1)
struct Node
{
    int l,r;
    int val;
    bool lazy;
    void update()
    {
        val=0;
        lazy=1;
    }
}o[maxn<<2];
void pushdown(int rt)
{
    if(o[rt].lazy)
    {
        o[ls].update();
        o[rs].update();
        o[rt].lazy=0;
    }
}
void pushup(int rt)
{
    o[rt].val=max(o[ls].val,o[rs].val);
}
void build(int rt,int l,int r)
{
    o[rt].l=l, o[rt].r=r;
    o[rt].lazy=0;
    if(l==r)
    {
        o[rt].val=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    pushup(rt);
}
void update(int rt,int st,int ed)
{
    if(st<=o[rt].l && o[rt].r<=ed)
    {
        o[rt].update();
        return;
    }
    pushdown(rt);
    int mid=(o[rt].l+o[rt].r)>>1;
    if(st<=mid) update(ls,st,ed);
    if(mid<ed) update(rs,st,ed);
    pushup(rt);
}
int query(int rt,int st,int ed)
{
    if(st<=o[rt].l && o[rt].r<=ed) return o[rt].val;
    pushdown(rt);
    int mid=(o[rt].l+o[rt].r)>>1;
    int res=0;
    if(st<=mid) res=max(res,query(ls,st,ed));
    if(mid<ed) res=max(res,query(rs,st,ed));
    pushup(rt);
    return res;
}

int main()
{
    cin>>n>>k;
    nxt[head=0]=1, pre[tail=n+1]=n;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        pos[a[i]]=i;
        pre[i]=i-1, nxt[i]=i+1;
    }

    build(1,1,n);
    bool team=0;
    while(1)
    {
        int mx=query(1,1,n);
        if(mx<=0) break;

        ans[pos[mx]]=team;
        int l=pos[mx], r=pos[mx];
        for(int i=1;i<=k;i++)
        {
            if(pre[l]==head) break;
            else l=pre[l], ans[l]=team;
        }
        for(int i=1;i<=k;i++)
        {
            if(nxt[r]==tail) break;
            else r=nxt[r], ans[r]=team;
        }
        update(1,l,r);
        int pre_l=pre[l], nxt_r=nxt[r];
        nxt[pre_l]=nxt_r, pre[nxt_r]=pre_l;

        team^=1;
    }

    for(int i=1;i<=n;i++) printf("%d",ans[i]+1);
}
相關文章
相關標籤/搜索