1. 程式人生 > >Codeforces 704A Thor (腦洞題)

Codeforces 704A Thor (腦洞題)

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 4
1 3
1 1
1 2
2 3
Output
1
2
3
2
Input
4 6
1 2
1 4
1 2
3 3
1 3
1 3
Output
1
2
3
0
1
2
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 second

const 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 second

const 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;
}