Codeforces 1154E - Two Teams - [线段树+链表]
题目链接: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); }
转载请注明出处:https://dilthey.cnblogs.com/