题目链接:https://codeforces.com/contest/1154/problem/E
题意:现在有一个数列包含n个数(1~n 乱序),你每次选择一个最大的数出来,然后将这个数向左删k个,向右删k个,超过了边界就停止,每次删的数轮流归教练1和教练2,删除之后要合并成一个新的数列,问最后所有的数的归属。
解题心得:一个很好想的题,将所有的数建立成双向链表,并且把所的数放在set里面,删除之后可以直接O(1)合并产生新的数列,O(logn)在set中删除,每次找最大的那个数可以直接使用set维护就行了。最终复杂度就是O(nlogn)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const int maxn = 2e5+100;
int ans[maxn], num[maxn], n, k;
struct Node {
int l, r, va, pos;
};
struct Node2 {
int va, pos;
bool operator < (const Node2 &a) const {
if(this->va != a.va) {
return this->va > a.va;
} else
return this->pos < a.pos;
}
Node2(){}
Node2(int va, int pos):
va(va), pos(pos){}
};
set <Node2> se;
Node ve[maxn];
void init() {
scanf("%d%d", &n, &k);
for(int i=1;i<=n;i++) {
scanf("%d", &num[i]);
se.insert(Node2(num[i], i));
ve[i].l = i-1;
ve[i].r = i+1;
ve[i].va = num[i];
ve[i].pos = i;
}
}
void erase(int x) {//双向链表删除一个节点
ve[ve[x].l].r = ve[x].r;
ve[ve[x].r].l = ve[x].l;
se.erase(Node2(ve[x].va, ve[x].pos));
}
void delete_to_left(int pos, int flag) {
for(int i=0;i<k;i++) {
pos = ve[pos].l;
if(pos == 0) break;
ans[pos] = flag;
erase(pos);
}
}
void delete_to_right(int pos, int flag) {
for(int i=0;i<k;i++) {
pos = ve[pos].r;
if(pos == n+1) break;
ans[pos] = flag;
erase(pos);
}
}
int main() {
// freopen("1.in", "r", stdin);
init();
int flag = 1;
while(!se.empty()) {
Node2 now = *se.begin();
int pos = now.pos;
se.erase(se.begin());
ans[pos] = flag;
erase(pos);
delete_to_left(pos, flag);
delete_to_right(pos, flag);
flag = !flag;
}
for(int i=1;i<=n;i++) {
if(ans[i] == 0) ans[i] += 2;
printf("%d", ans[i]);
}
return 0;
}