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+; 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=;
lazy=;
}
}o[maxn<<];
void pushdown(int rt)
{
if(o[rt].lazy)
{
o[ls].update();
o[rs].update();
o[rt].lazy=;
}
}
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=;
if(l==r)
{
o[rt].val=a[l];
return;
}
int mid=(l+r)>>;
build(ls,l,mid);
build(rs,mid+,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)>>;
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)>>;
int res=;
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=]=, pre[tail=n+]=n;
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
pos[a[i]]=i;
pre[i]=i-, nxt[i]=i+;
} build(,,n);
bool team=;
while()
{
int mx=query(,,n);
if(mx<=) break; ans[pos[mx]]=team;
int l=pos[mx], r=pos[mx];
for(int i=;i<=k;i++)
{
if(pre[l]==head) break;
else l=pre[l], ans[l]=team;
}
for(int i=;i<=k;i++)
{
if(nxt[r]==tail) break;
else r=nxt[r], ans[r]=team;
}
update(,l,r);
int pre_l=pre[l], nxt_r=nxt[r];
nxt[pre_l]=nxt_r, pre[nxt_r]=pre_l; team^=;
} for(int i=;i<=n;i++) printf("%d",ans[i]+);
}
Codeforces 1154E - Two Teams - [线段树+链表]的更多相关文章
- Buses and People CodeForces 160E 三维偏序+线段树
Buses and People CodeForces 160E 三维偏序+线段树 题意 给定 N 个三元组 (a,b,c),现有 M 个询问,每个询问给定一个三元组 (a',b',c'),求满足 a ...
- CodeForces 877E DFS序+线段树
CodeForces 877E DFS序+线段树 题意 就是树上有n个点,然后每个点都有一盏灯,给出初始的状态,1表示亮,0表示不亮,然后有两种操作,第一种是get x,表示你需要输出x的子树和x本身 ...
- [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)
[Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...
- [Codeforces 1199D]Welfare State(线段树)
[Codeforces 1199D]Welfare State(线段树) 题面 给出一个长度为n的序列,有q次操作,操作有2种 1.单点修改,把\(a_x\)修改成y 2.区间修改,把序列中值< ...
- [Codeforces 316E3]Summer Homework(线段树+斐波那契数列)
[Codeforces 316E3]Summer Homework(线段树+斐波那契数列) 顺便安利一下这个博客,给了我很大启发(https://gaisaiyuno.github.io/) 题面 有 ...
- CF 552(div 3) E Two Teams 线段树,模拟链表
题目链接:http://codeforces.com/contest/1154/problem/E 题意:两个人轮流取最大值与旁边k个数,问最后这所有的数分别被谁给取走了 分析:看这道题一点思路都没有 ...
- Codeforces Gym 100231B Intervals 线段树+二分+贪心
Intervals 题目连接: http://codeforces.com/gym/100231/attachments Description 给你n个区间,告诉你每个区间内都有ci个数 然后你需要 ...
- Codeforces 482B Interesting Array(线段树)
题目链接:Codeforces 482B Interesting Array 题目大意:给定一个长度为N的数组,如今有M个限制,每一个限制有l,r,q,表示从a[l]~a[r]取且后的数一定为q,问是 ...
- codeforces 383C Propagating tree 线段树
http://codeforces.com/problemset/problem/383/C 题目就是说, 给一棵树,将一个节点的值+val, 那么它的子节点都会-val, 子节点的子节点+val. ...
随机推荐
- String总结
- hiho 1098 最小生成树二·Kruscal算法 (最小生成树)
题目: 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 随着小Hi拥有城市数目的增加,在之间所使用的Prim算法已经无法继续使用了——但是幸运的是,经过计算机的分析, ...
- web开发简史与技术选型
视频地址:http://v.youku.com/v_show/id_XMTQxNzM1MzAwOA==.html?firsttime=0&from=y1.4-2
- C++入门篇三
引用:& &放在左边就是引用,放在右边就是取地址 int main() { //引用的类型必须相同,一经引用,不可以在被引用 ; int &b = a;//b引用a之后,两个同 ...
- sklearn.linear_model.LinearRegresion学习
sklearn线性模型之线性回归 查看官网 https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearR ...
- Google Android SDK开发范例大全笔记 一
方法讲解 1 获取手机分辨率方法 DisplayMetrics private void getDiaplayMetrics() { DisplayMetrics dm = new DisplayMe ...
- 1、在Centos上安装Grafana
1.如果你想将老版本的Grafana升级为新版本的Grafana,可以阅读链接中的文档指南: http://docs.grafana.org/installation/upgrading/ 2.使用y ...
- C/S,B/S应用的区别
——————C/S,B/S应用的区别 C/S是指客户端/服务器架构,是一种典型的两层架构,可充分发挥客户端pc的性能,相对减轻服务器的压力. B/S是指浏览器/服务器架构,区别于传统的C/S(客户端/ ...
- 源码安装cx_Oracle(适合离线环境)
cd ~/tools unzip instantclient-basic-linux.x64-12.2.0.1.0.zip mv instantclient_12_2 /opt/ export ORA ...
- 迭代DOM集合的几种方法
1. Array.prototype.slice.call() 转数组再遍历 var a= document.querySelectorAll('div'); var arr = Array. ...