Codeforces 704A Thor (脑洞题)

来源:互联网 发布:网络社会治理的方针 编辑:程序博客网 时间:2024/05/22 05:18
A. Thor
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Thor is getting used to the Earth. As a gift Loki gave him a smartphone. There aren applications on this phone. Thor is fascinated by this phone. He has only one minor issue: he can't count the number of unread notifications generated by those applications (maybe Loki put a curse on it so he can't).

q events are about to happen (in chronological order). They are of three types:

  1. Application x generates a notification (this new notification is unread).
  2. Thor reads all notifications generated so far by application x (he may re-read some notifications).
  3. Thor reads the first t notifications generated by phone applications (notifications generated in firstt events of the first type). It's guaranteed that there were at leastt events of the first type before this event. Please note that he doesn't read firstt unread notifications, he just reads the very firstt notifications generated on his phone and he may re-read some of them in this operation.

Please help Thor and tell him the number of unread notifications after each event. You may assume that initially there are no notifications in the phone.

Input

The first line of input contains two integers n andq (1 ≤ n, q ≤ 300 000) — the number of applications and the number of events to happen.

The next q lines contain the events. Thei-th of these lines starts with an integertypei — type of thei-th event. If typei = 1 ortypei = 2 then it is followed by an integerxi. Otherwise it is followed by an integerti (1 ≤ typei ≤ 3, 1 ≤ xi ≤ n, 1 ≤ ti ≤ q).

Output

Print the number of unread notifications after each event.

Examples
Input
3 41 31 11 22 3
Output
1232
Input
4 61 21 41 23 31 31 3
Output
123012
Note

In the first sample:

  1. Application 3 generates a notification (there is1 unread notification).
  2. Application 1 generates a notification (there are2 unread notifications).
  3. Application 2 generates a notification (there are3 unread notifications).
  4. Thor reads the notification generated by application 3, there are2 unread notifications left.

In the second sample test:

  1. Application 2 generates a notification (there is1 unread notification).
  2. Application 4 generates a notification (there are2 unread notifications).
  3. Application 2 generates a notification (there are3 unread notifications).
  4. Thor reads first three notifications and since there are only three of them so far, there will be no unread notification left.
  5. Application 3 generates a notification (there is1 unread notification).
  6. Application 3 generates a notification (there are2 unread notifications).


题目大意:

    有一个笨蛋不会数手机通知的条数,让你帮助它。有3种操作。

1、第x个应用增加条消息。

2、阅读第x个应用的全部消息。

3、阅读全部消息(包括已经读过的)前x条消息。

    每次操作后输出未读消息数。


解题思路:

    比赛时,第一眼看到这个题第一感觉就是数据结构题,然后想怎么用树状数组或者线段数写。不过想了一段时间发现无法同时高效的同时进行第二组或第三组操作。这时听别人说用链表,或vector没TLE,然后马上用链表模拟每个app暴力写了一下。竟然T了,然后就不知道哪里来的自信,觉得自己方法没错。就一直想办法优化。最终TLE到比赛结束。掉分GG。

    比赛后看了一眼官方题解。马上就发现了自己比赛的时候有多么蠢,比赛的时候只要再稍微分析一下复杂度的来源,马上就可以A。

    还是模拟。每个app用一个队列保存未读的通知,用一个队列用时间顺序保存未读的通知,再开一个bool数组表示每个时间的消息是否已读。

    对于第一种操作,总数加一,对应app队列push这个时间,时间队列push一个保存时间和app编号的pair。

    第二种操作:把对应的app队列扫一遍,并把每个元素弹出,如果这个通知未读,就总数减一,对应bool置true。

    第三种操作:把时间队列不断向后扫,并弹出元素,直到时间大于x,如果这个消息未读,对应app弹出第一个元素,总数减一,bool置true。

    然后在每次操作后输出总数即可,核型思想就是尽量弹出已读消息,并用时间队列避免对app的遍历。这样即可在O(Q)的时间内完成。


TLE代码

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <cmath>#include <string>#include <vector>#include <queue>#include <list>using namespace std;#define INF 0x3f3f3f3f#define LL long long#define fi first#define se secondconst int maxn=300000+3;int N,Q;list<int> app[maxn];int main(){    scanf("%d%d",&N,&Q);    int sum=0;    int order=0;    for(int i=0;i<Q;++i)    {        int t,x;        scanf("%d%d",&t,&x);        if(t==1)        {            ++order;            ++sum;            app[x].push_back(order);        }        else if(t==2)        {            sum-=app[x].size();            app[x].clear();        }        else        {            for(int i=1;i<=N;++i)            {                while(true)                {                    if(app[i].begin()==app[i].end())                        break;                    if(*(app[i].begin())<=x)                    {                        --sum;                        app[i].pop_front();                    }                    else break;                }            }        }        printf("%d\n",sum);    }        return 0;}


AC代码:

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <cmath>#include <string>#include <vector>#include <queue>#include <list>#include <map>using namespace std;#define INF 0x3f3f3f3f#define LL long long#define fi first#define se secondconst int maxn=300000+3;int N,Q;queue<int> app[maxn];//记录每个应用的通知队列queue<pair<int,int> > tim;//记录时间的通知队列。(时间,类型)bool vis[maxn];//标记每个消息是否已经读过int main(){    scanf("%d%d",&N,&Q);    int sum=0;    int order=0;//标记是第几个通知    for(int i=0;i<Q;++i)    {        int t,x;        scanf("%d%d",&t,&x);        if(t==1)//操作1        {            ++order;            ++sum;            app[x].push(order);            tim.push(make_pair(order,x));        }        else if(t==2)//操作2        {            while(!app[x].empty())            {                if(!vis[app[x].front()])                {                    --sum;                    vis[app[x].front()]=true;                }                app[x].pop();            }        }        else//操作3        {            while(!tim.empty()&&tim.front().fi<=x)            {                if(!vis[tim.front().fi])                {                    --sum;                    vis[tim.front().fi]=true;                    app[tim.front().se].pop();//从应用通知队列中去掉这个通知                }                tim.pop();            }        }        printf("%d\n",sum);    }        return 0;}


0 0
原创粉丝点击