您的位置:首页 > 其它

CF 704A Thor

2016-08-18 22:26 211 查看

description

这道题是说一共有m个操作(M<=100000),操作分为3种,对于第一种操作,在队列末尾加入一个正整数x(X<=100000),对于操作二,将队列中权值为x的值全部标为0,但并不踢出队列,对于操作三,将队列的前i个全部标为0。也就是说,一个点有可能被重复标为0。对于每个操作,求操作后剩余多少个不为0的数。

Solution

一开始就想到了线段树,但后来才发现其实是不需要的,只感觉自己蠢了。。。

对于操作1,我们在一个桶中在x的位置上加1,并给答案加1,并在队列中加入这个数,尾指针右移。

而对于操作二,我们直接将答案减去桶中x位置上的值,并将这个值清空,将对x最新的一次操作定为现在队列的尾指针即可。

对于操作三,我们将头指针到i的数逐个判断,看它最新的一次操作是否大于它自己的位置,假如不是就将它减去,并更新桶的值和答案,将头指针与i取个较大值赋为头指针的新值。

Tips:看起来这样做一次操作是O(N)的,实则不然。对于队列里的每个数,我只要查过一次以后就再也不会再次查询,关键就在于对于每次操作三后头指针与i取个较大值作为头指针的新值,所以整个的复杂度是O(N)的。

代码

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=300005;
int f[maxn],d[maxn],b[maxn],c[maxn],a[maxn],n,m,i,t,j,k,l,x,y,tot,ans;
int main(){
//  freopen("data.in","r",stdin);freopen("data.out","w",stdout);
scanf("%d%d",&n,&m);tot=1;
for (i=1;i<=m;i++){
scanf("%d%d",&x,&y);
if (x==1) d[++d[0]]=y,c[y]=d[0],a[y]++,ans++;
else if (x==2) b[y]=c[y],ans-=a[y],a[y]=0;
else{
for (j=tot;j<=y;j++)
if (b[d[j]]<j) a[d[j]]--,ans--,b[d[j]]=j;
tot=max(tot,y+1);
}
printf("%d\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: