题目链接:买票问题
思路:优先队列维护忍耐度最低的人在队首,leave操作ok.
vis数组记录从1到n的编号的人们是不是在队列中,top维护队首的人的编号。pop操作搞定。
然后,check操作就是在vis数组中查找当前编号之前有多少个为1的数,树状数组大法好。
啊...数据虽然很大,但是t<=100000,所以可以用map把所有的编号标记为1-100000之间的...
dbug全程:开始树状数组求和错误,检查模板没错,后猛然想起,树状数组每次更新i处的值,所有小于maxn的i + lowbit(i)都要更新,所以,sum()函数里,while(i<=maxn) 而不是当前最大位置num。然后发现RE,用mp数组映射的时候,mp[int] = num++; 显然mp数组越界了。果断该成map。大概这就是map的好处吧...然后TLE,我拒绝相信!然后发现队列没有清空,直接开在main函数了,AC之。尝试把队列开成全局变量,然后main函数里清空,依然TLE。
大概,STL用的太多了吧..........
附代码:
/* 不想敲题,不想敲题,这道题真丑~躺在地上打滚中... 思路:优先队列维护忍耐度最低的人在队首,leave操作ok. vis数组记录从1到n的编号的人们是不是在队列中,top维护队首的人的编号。pop操作搞定。 然后,check操作就是在vis数组中查找当前编号之前有多少个为1的数,树状数组大法好。 啊...数据虽然很大,但是t<=100000,所以可以用map把所有的编号标记为1-100000之间的... 讲真,为什么dangshixiangbuchulaine... */ #include <stdio.h> #include <string.h> #include <iostream> #define maxn 100005 #include <map> #include <queue> using namespace std; char op[10]; int vis[maxn]; map<int, int>mp; int a[maxn]; int num; struct Node { int id, endu; friend bool operator < (Node a, Node b) { return a.endu > b.endu; // 从小到大 } Node(int id, int endu) { this->id = id, this->endu = endu; } }; int lowbit(int x) { return x & (-x); } int sum(int id) { int ans = 0; while(id > 0) { ans += a[id]; id -= lowbit(id); } return ans; } void update(int id, int x) { while(id <= maxn) { a[id] += x; id += lowbit(id); } } int main() { int n; while(~scanf("%d", &n)) { mp.clear(); num = 1; // 编号 memset(vis, 0, sizeof(vis)); memset(a, 0, sizeof(a)); priority_queue<Node> que; int top = 0; for (int i=0; i<n; ++i) { scanf("%s", op); if (op[0] == 'a') { int id, endu; scanf("%d%d", &id, &endu); mp[id] = num++; id = mp[id]; vis[id] = 1; update(id, 1); Node temp(id, endu); que.push(temp); } else if (op[0] == 'l') { while(!que.empty() && !vis[que.top().id]) que.pop(); if (!que.empty() && vis[que.top().id]) { int lid = que.top().id; que.pop(); vis[lid] = 0; update(lid, -1); } } else if (op[0] == 'p') { while(!vis[top] && top<num) top++; if (top < num && vis[top]) { vis[top] = 0; update(top, -1); } } else { int tid, tendu; scanf("%d%d", &tid, &tendu); tid = mp[tid]; if (vis[tid]) { int tsum = sum(tid); tsum -= 1; printf("%d\n", tsum); if (tsum > tendu) { vis[tid] = 0; update(tid, -1); } } } } } return 0; }
不然,把struct改成pair好了...
附代码:
/* 不想敲题,不想敲题,这道题真丑~躺在地上打滚中... 思路:优先队列维护忍耐度最低的人在队首,leave操作ok. vis数组记录从1到n的编号的人们是不是在队列中,top维护队首的人的编号。pop操作搞定。 然后,check操作就是在vis数组中查找当前编号之前有多少个为1的数,树状数组大法好。 啊...数据虽然很大,但是t<=100000,所以可以用map把所有的编号标记为1-100000之间的... 讲真,为什么dangshixiangbuchulaine... */ #include <stdio.h> #include <string.h> #include <iostream> #define maxn 100005 #include <map> #include <queue> using namespace std; char op[10]; int vis[maxn]; map<int, int>mp; int a[maxn]; int num; typedef pair<int, int>Per; int lowbit(int x) { return x & (-x); } int sum(int id) { int ans = 0; while(id > 0) { ans += a[id]; id -= lowbit(id); } return ans; } void update(int id, int x) { while(id <= maxn) { a[id] += x; id += lowbit(id); } } int main() { int n; while(~scanf("%d", &n)) { mp.clear(); num = 1; // 编号 memset(vis, 0, sizeof(vis)); memset(a, 0, sizeof(a)); priority_queue<Per, vector<Per>, greater<Per> > que; // 从小到大 int top = 0; Per per; for (int i=0; i<n; ++i) { scanf("%s", op); if (op[0] == 'a') { int id, endu; scanf("%d%d", &id, &endu); mp[id] = num++; id = mp[id]; vis[id] = 1; update(id, 1); per = make_pair(endu, id); que.push(per); } else if (op[0] == 'l') { while(!que.empty() && !vis[que.top().second]) que.pop(); if (!que.empty() && vis[que.top().second]) { int lid = que.top().second; que.pop(); vis[lid] = 0; update(lid, -1); } } else if (op[0] == 'p') { while(!vis[top] && top<num) top++; if (top < num && vis[top]) { vis[top] = 0; update(top, -1); } } else { int tid, tendu; scanf("%d%d", &tid, &tendu); tid = mp[tid]; if (vis[tid]) { int tsum = sum(tid); tsum -= 1; printf("%d\n", tsum); if (tsum > tendu) { vis[tid] = 0; update(tid, -1); } } } } } return 0; }