男儿何不带吴钩,收取关山五十州。
征战天下是秋实大哥一生的梦想,所以今天他又在练习一个对战游戏。
秋实大哥命令所有士兵从左到右排成了一行来抵挡敌人的攻击。
敌方每一次会攻击一个士兵,这个士兵就会阵亡,整个阵列就会从这个位置断开;同时有的时候已阵亡的士兵会受人赢气息感染而复活。
秋实大哥想知道某一时刻某一个士兵所在的阵列的长度是多少。
Input
第一行包含两个整数 n , m ,表示秋实大哥的士兵数目和接下来发生的事件数目。
接下来 m 行,每一行是以下三种事件之一:
0 x : 表示x位置的士兵受到攻击阵亡 1 x : 表示x位置的士兵受人赢气息感染复活 2 x : 秋实大哥想知道第x个士兵所在阵列的长度
1≤n,m≤100000 , 1≤x≤n。
Output
对于每一个 2 x 事件,输出对应的答案占一行。
Sample input and output
Sample Input | Sample Output |
---|---|
5 3 2 2 0 3 2 2 | 5 2 |
#include <iostream>
#include <cstdio>
#include <list>
using namespace std;
list<int> l;
void die(int x)
{
list<int>::iterator l1,l2;
l2 = l.end();
for(l1 = l.begin();x > *l1 && l1 != l2;l1++);
if(x != *l1)
l.insert(l1, x);
}
void re(int x)
{
list<int>::iterator l1,l2;
l2 = l.end();
for(l1 = l.begin();x != *l1 && l1 != l2;l1++);
l.erase(l1);
}
int main()
{
int n,m,x,p;
scanf("%d%d",&n,&m);
l.push_back(0);
l.push_back(n+1);
while(m --){
scanf("%d%d",&p,&x);
if(p == 0)
die(x);
else if(p == 1)
re(x);
else{
list<int>::iterator l1,l2,l3;
l2 = l.end();
for(l1 = l.begin();x > *l1 && l1 != l2;l1++);
if(x == *l1){
printf("0\n");
continue;
}
l3 = l1;
l3 --;
printf("%d\n",*l1 - *l3 - 1);
}
}
return 0;
}
用list实现(后来发现用set好像更优)。
一共n个士兵,先将0和n+1加入链表,当有士兵死亡时,将死亡士兵的位置加入链表,并保证链表按升序排列。当某士兵复活时,从链表中删除该士兵的位置。询问士兵所在阵列长度时,从头至尾遍历链表,找出被询问士兵所在区间,通过两边死亡士兵位置或边界位置相减再减1,得到阵列长度。
需要特别注意加以判断的有两点,一是死亡的士兵还可能被攻击,但是链表中不能再加一个,这种情况在死亡士兵加入链表时加以判断,保证其不在链表中才能加入,否则不加入。另一个是死亡的士兵可能被询问,当死亡士兵被询问时,输出0,故在询问中多加条判断。