ZOJ 3888 Twelves Monkeys (优先队列+预处理)
tags: acm
其实是挺简单的题,就是要找次小值.但是我开始的时候没想到用优先队列,强行暴力维护TLE了两遍,优化矬了WA一次,无奈改用优先队列后又错了好几次,后来花了好长时间(真的很久)才发现忘记重载小于号了(那时候我就觉得自己是一个煞笔orz)最后终于AC.
题意:
有M个时间机器,每个时间机器能让你从x年回到y年( 1≤y≤x≤n≤50000 ).现在你有一次使用时间机器的机会,问有哪些年你有两种方法到达.每组输入有多个询问,每个询问输入当前年份.
解析:
假如当前年份为p,则可以使用所有x值大于等于p的时间机器.而在这些机器中,我们只需要关注y值最小的两个就好了.y的最小值到当前年份之间的年份可以访问一次,而y次小值到当前年份之间能被访问两次.因此整个问题就转化为找到x>=p的时间机器中y第二小的那个.需要注意的是存在次小值大于p的情况.由于询问较多,我们可以先进行一次预处理,得到[1,n]范围内的所有p值对应的答案,将其存在ans[p]中,询问时输出对应的答案即可.
据说还可以用线段树(主席树)来做,不过我不是很明白,也没再多花时间了.
代码:
运行时间:550ms
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define MAXN 50000+100
using namespace std;
struct E
{
int from, to;
}arc[MAXN];
bool operator < (E a, E b)
{
if (a.from != b.from)
return a.from > b.from;
return a.to < b.to;
}
struct node
{
int x;
node(int xx=0) { x = xx; }
}nnode;
bool operator < (node a, node b)
{
return a.x>b.x;
}
int ans[MAXN];
int main()
{
int N, M, q;
while (scanf("%d%d%d", &N, &M, &q) != EOF)
{
for (int i = 0; i < M; i++)
{
scanf("%d%d", &arc[i].from, &arc[i].to);
}
sort(arc, arc + M);
priority_queue<node> Q;
memset(ans, 0, sizeof(ans));
int pos = 0;
for (int i = N; i >= 0; i--)
{
while (pos < M && arc[pos].from >= i)
{
nnode.x = arc[pos++].to;
Q.push(nnode);
}
if (Q.size() >= 2)
{
int m1 = Q.top().x;
Q.pop();
int m2 = Q.top().x;
Q.pop();
if (m2 <= i)
{
ans[i] = i - m2;
}
else
ans[i] = 0;
Q.push(m1);
Q.push(m2);
}
else
ans[i] = 0;
}
int k;
for (int i = 0; i < q; i++)
{
scanf("%d", &k);
printf("%d\n", ans[k]);
}
}
return 0;
}