Codeforces #669 Div2 E. Little Artem and Time Machine(离线、优先队列)

题目链接:
Codeforces #669 Div2 E. Little Artem and Time Machine
题意:
定义一个元素重复集合multiset,然后在不同的时间对集合添加和删除元素操作,需要输出在不同的查询时间集合中元素出现的次数。
分析;
离线处理。首先将查询按照查询时间排序,然后检查所有在这个查询的输入之前的操作,
如果操作时间小于查询时间那么就执行,否则就存进一个优先队列中,等到时间够了再执行。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#include <queue>
#include <map>
#include <vector>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0)
using namespace std;
const int MAX_N=100010;

int n,total1,total2;

struct Query{
    int id,step,data,ans;
}query[MAX_N];

struct Oper{
    int id,step,data,flag;
    //bool operator < (const Oper& rhs) const{
    //  return step > rhs.step;
    //}
};
Oper oper[MAX_N];

bool cmp1(struct Query a,struct Query b)
{
    return a.step<b.step;
}

bool cmp2(struct Query a,struct Query b)
{
    return a.id < b.id;
}

struct cmp { //cmp比较函数,a<b返回1,否则返回0
    bool operator () (const Oper& a,const Oper& b) const {
        //因为优先队列是“大”的元素先出来,我们需要的是step小的先出来,只能定义a.step>b.step时a<b
        return a.step > b.step;
    }
};

int main()
{
    freopen("Ein.txt","r",stdin);
    while(~scanf("%d",&n)){
        map<int,int> mp;
        total1=total2=0;
        for(int i=0;i<n;i++){
            int t,a,b;
            scanf("%d%d%d",&t,&a,&b);
            if(t==1||t==2){
                oper[total1].flag=(t==1?1:0); // 1.添加  0.删除
                oper[total1].step=a;
                oper[total1].data=b;
                oper[total1].id=i;
                total1++;
            } else {
                query[total2].step=a;
                query[total2].data=b;
                query[total2].id=i;
                total2++;
            }
        }

        sort(query,query+total2,cmp1); //按照查询的时间排序
        priority_queue < Oper,vector<Oper>, cmp>  que; //定义操作时间在前的先出的优先队列

        for(int i=0,j=0;j<total2;j++){
            while(i<total1 && oper[i].id < query[j].id){ //将所有在这次查询的输入之前的操作执行
                int step=oper[i].step;
                if(step>query[j].step){ //如果这次操作是在这次查询之后执行的
                    que.push(oper[i]);  //先存进优先队列中
                }else {
                    if(oper[i].flag==1) mp[oper[i].data]++;  //添加元素
                    else mp[oper[i].data]--; //删除元素
                }
                i++;
            }
            while(1){ //查找之前操作中的所有操作时间在查询时间之前的操作
                if(que.empty()) break;
                Oper tmp=que.top();
                //printf("tmp.step=%d \n",tmp.step);
                if(tmp.step < query[j].step){
                    que.pop();
                    if(tmp.flag==1) mp[tmp.data]++;
                    else mp[tmp.data]--;
                }else {
                    break;
                }
            }
            query[j].ans=mp[query[j].data];
        }

        sort(query,query+total2,cmp2); //按照查询的输入顺序排序
        for(int i=0;i<total2;i++){
            printf("%d\n",query[i].ans);
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值