题面
思路
各个数组的作用
idx[i]
表示能力为i
的人的所在位置,vis[i]
表示位置i
的人所在的队伍,m[i].pre
和m[i].nxt
分别为上一个结点的位置和下一个结点的位置
int vis[maxn], idx[maxn]; // 记录答案,记录每个值在链表中的位置
struct node {
int pre, nxt; // 双向静态链表
} m[maxn];
删除结点
删除下表为
i
d
id
id的结点就是把上一个vis[id].pre
结点的下一个节点vis[id].nxt
更改,并把下一个节点的上一个节点更改即可,并给`vis[id]·赋值
void Del(int id, int flag) { // 将下标为 id 的结点删除(vis 标记为flag)
m[m[id].pre].nxt=m[id].nxt;
m[m[id].nxt].pre=m[id].pre;
vis[id]=flag;
}
初始化
把每个队员看作一个链表上的一个节点,由于每个人的能力是 1 1 1~ n n n,用桶排序直接得到每个人的能力, i d x [ i ] idx[i] idx[i]表示第 i i i大的人在第几位
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
idx[x]=i;
m[i].pre=i-1;
m[i].nxt=i+1;
}
删除相应节点
void Del(int id, int flag) { // 将下标为 id 的结点删除(vis 标记为flag)
// 请在下面补充代码
m[m[id].pre].nxt=m[id].nxt;
m[m[id].nxt].pre=m[id].pre;
vis[id]=flag;
}
计算过程
逐个枚举当前最大的数值,如果当前数值不存在就直接继续
分别枚举往前的,当到达尽头就停
向后的,当到达结尾就停
最后,别忘了标记当前这位
int cnt = 0, flag = 1;
for (int i = n; i >= 1; i--) {
if (vis[idx[i]]) {
continue;
}
int id=idx[i];
for(int j=1;j<=k && m[id].pre!=0;j++){
id=m[id].pre;
Del(id,flag);
}
id=idx[i];
for(int j=1;j<=k && m[id].nxt!=n+1;j++){
id=m[id].nxt;
Del(id,flag);
}
Del(idx[i],flag);
flag = flag == 1 ? 2 : 1;
}
实现代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int n, k;
int vis[maxn], idx[maxn]; // 记录答案,记录每个值在链表中的位置
struct node {
int pre, nxt; // 双向静态链表
} m[maxn];
void Del(int id, int flag) { // 将下标为 id 的结点删除(vis 标记为flag)
m[m[id].pre].nxt=m[id].nxt;
m[m[id].nxt].pre=m[id].pre;
vis[id]=flag;
}
int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
idx[x]=i;
m[i].pre=i-1;
m[i].nxt=i+1;
}
int cnt = 0, flag = 1;
for (int i = n; i >= 1; i--) {
if (vis[idx[i]]) {
continue;
}
int id=idx[i];
for(int j=1;j<=k && m[id].pre!=0;j++){
id=m[id].pre;
Del(id,flag);
}
id=idx[i];
for(int j=1;j<=k && m[id].nxt!=n+1;j++){
id=m[id].nxt;
Del(id,flag);
}
Del(idx[i],flag);
flag = flag == 1 ? 2 : 1;
}
for (int i = 1; i <= n; i++) {
printf("%d", vis[i]);
}
return 0;
}