• Codeforces 1154E


    题目链接:https://codeforces.com/contest/1154/problem/E

    题意:

    $n$ 个人排成一排,第 $i$ 个人的能力值为 $a[i]$,$a[1 sim n]$ 是 $1 sim n$ 的某个排列。

    第一个教练先来拉人,他会拉目前还在队伍中的 $a[i]$ 最高的那个人,并且把排在它前面和后面的各自 $k$ 个人都拉走,即最多可以拉走 $2k + 1$ 个人。

    然后,第二个教练来拉人,也是同样的操作。注意,如果当前被拉走的人的前面或者后面不足 $k$ 个人,那就尽可能多地拉人。

    两个教练轮流拉人,直到整个队伍中一个人都不剩。要求你给出最后每个人被哪个教练拉走了。

    题解:

    老年手速选手,时间紧没写完……

    一开始先考虑直接用一个线段树搞定,发现有点难……而且时间复杂度也不一定能过。

    后来,考虑加入一个链表来维护目前的这一排队伍。

    我们用线段树维护这 $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);
    }
  • 相关阅读:
    BZOJ2809 dispatching
    BZOJ1486 最小圈
    BZOJ1096 仓库建设
    BZOJ3190 赛车
    BZOJ1911 特别行动队
    BZOJ1202 狡猾的商人
    BZOJ1007 水平可见直线
    BZOJ2150 部落战争
    如何用PHP遍历文件数目 或删除目录下的全部文件?
    php对文件/目录操作的基础知识(图解)
  • 原文地址:https://www.cnblogs.com/dilthey/p/10721176.html
Copyright © 2020-2023  润新知