CF1320E (虚树)
考试那天是倒霉的一天, 模拟赛莫名爆炸, 班会课被老师拉起来总结, 忙活一天作业没有写完, 晚上打cf一开始挺顺利, 考试结束前三分钟第一题被hack(不过我把数组开大些重新交一遍就过了, 但分数掉了一大堆), e题想出来了但没有写完.... 我太难了
好吧, 言归正传
题目大意
你现在有一棵边权都为1树, 每个点都是一个城市, 有q次询问, 每次讯问中有(k_i)个城市感染不同的病毒, 病毒一旦感染就不会恢复并且感染病毒的城市不会再被其他病毒感染, 每个病毒有传播速度(s_i), 传播方式比较奇怪, 每一回合内, 一号病毒开始传播(从它已经感染的城市x), 距离x小于(s_i)的将全部被感染(以前感染过的不算), 然后是二号三号...也就是说传染过程不是同时进行的, 而是一轮一轮的, 接下来你有(m_i)个重要城市, 问这(m_i)个城市被哪种病毒感染
数据范围
(1 le n, q, sum k_i, sum m_i le 200000)
这题关键词"重要的城市"和(sum)的数据范围已经暴露了它就是个虚树, 因为其他点对我们来说是不重要的, 首先我们把虚树建出来, 模板不多说. 然后就是以下问题:
你有一棵树, 有一些点已经被感染了, 每条边有边权, 求这棵树所有的点被哪种病毒感染 问题就简单多了吧
我会bfs!
不难发现每种病毒的感染区域是一个连通块, 直接从每个点bfs就行了嘛, 事实上不好bfs, 因为题目中按时间转移的性质使bfs在处理边权时不太好做, 有精力的同学可以一试, 不过我挂了
我会spfa!
设每个点的状态是({感染时间, 病毒种类, 病毒到达该点时的回合中从该点还可以走几步}) 最后走几步的意思就是您在一个回合内感染到一个点, 然而因为是虚树有边权, 所以可能停在某个点还剩着一些步数. 所以您下一次从新感染点扩展时, 范围可以加上上回没走完的步数.
这样的话, 根据题意, 优先级是感染时间越早越好, 种类最小越好, 步数越多越好. 如果用spfa转移应该没啥问题.
然而还是有一些小问题就是先感染的病毒会挡住别的病毒感染的去路, 而spfa是没有顺序的, 结果就是编号大的病毒先感染以后, 编号小的本可以挡住它, 可因为速度慢一些, 因时间无法将他更新.
真•正解
根据以上分析不难想到正解, spfa不行就用diji呗(滑稽
我们可以用优先队列来bfs, 这样每次更新进来的点都是较优的, 从队列中取出来的时候就是最优解了, 这么简单我怎么一开始没想到QAQ
代码:
#pragma GCC optimize(3)
#pragma GCC optimize("inline")
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include <queue>
#define ll long long
using namespace std;
const int N = 1005000;
template <typename T>
void read(T &x) {
x = 0; bool f = 0;
char c = getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
for (;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^48);
if (f) x=-x;
}
int n, m;
int h[N], ne[N], to[N];
int dep[N], tot;
inline void add(int x, int y) {
ne[++tot] = h[x], to[h[x] = tot] = y;
}
int siz[N], f[N], son[N];
int Top[N], a[N], s[N], top;
void dfs1(int x, int fa) {
siz[x] = 1, f[x] = fa, dep[x] = dep[fa] + 1;
for (int i = h[x]; i; i = ne[i]) {
int y = to[i]; if (y == fa) continue;
dfs1(y, x), siz[x] += siz[y];
if (siz[y] > siz[son[x]]) son[x] = y;
}
}
int dfn[N], num;
void dfs2(int x, int topf) {
Top[x] = topf, dfn[x] = ++num;
if (!son[x]) return;
dfs2(son[x], topf);
for (int i = h[x]; i; i = ne[i])
if (!dfn[to[i]]) dfs2(to[i], to[i]);
}
int Lca(int x, int y) {
while (Top[x] != Top[y]) {
if (dep[Top[x]] < dep[Top[y]]) swap(x, y);
x = f[Top[x]];
}
return dep[x] < dep[y] ? x : y;
}
bool cmp(int a, int b) {
return dfn[a] < dfn[b];
}
vector <int> v[N];
inline void add_e(int x,int y) {
v[x].push_back(y); v[y].push_back(x);
}
void ins(int x) {
if (top == 1) return (void)(s[++top] = x);
int lca = Lca(x, s[top]);
if (lca == s[top]) return (void)(s[++top] = x);
while (top > 1 && dfn[s[top-1]] >= dfn[lca]) add_e(s[top-1], s[top]), top--;
if (lca != s[top]) add_e(lca, s[top]), s[top] = lca;
s[++top] = x;
}
int ask[N], vis[N];
struct node {
int col, v, di, ti;
bool operator < (const node &j) const{
if (ti != j.ti) return ti < j.ti;
if (col != j.col) return col < j.col;
return di > j.di;
}
}qaq[N], I;
inline int Dis(int x, int y) {
return dep[x] + dep[y] - 2 * dep[Lca(x, y)];
}
node To(int x, int y) {
int dis = Dis(x, y);
node tmp = qaq[x];
if (dis <= qaq[x].di) {
tmp.di -= dis; return tmp;
}
dis -= qaq[x].di;
int t = (dis - 1) / qaq[x].v + 1;
tmp.di = t * qaq[x].v - dis, tmp.ti += t;
return tmp;
}
struct QWQ {
node p; int x;
bool operator < (const QWQ &j) const { return j.p < p; }
};
priority_queue<QWQ> q;
int T;
inline bool Cmp(node a, QWQ b) { return a < b.p; }
void diji(void) {
while (q.size()) {
QWQ x = q.top(); q.pop();
if (Cmp(qaq[x.x], x)) continue;
for (auto y: v[x.x]) {
node t = To(x.x, y);
if (t < qaq[y]) {
qaq[y] = t; q.push((QWQ){qaq[y], y});
}
}
}
}
void refresh(int x, int f) {
for (auto i: v[x]) {
if (i == f) continue;
refresh(i, x);
}
v[x].clear(); qaq[x] = I;
}
void init(int m, int k) {
int cnt = m;
for (int i = 1;i <= m; i++) {
read(a[i]), qaq[a[i]].col = i, read(qaq[a[i]].v);
qaq[a[i]].ti = 0; q.push((QWQ){qaq[a[i]], a[i]});
}
for (int i = 1;i <= k; i++)
read(ask[i]), a[++cnt] = ask[i];
sort(a + 1, a + cnt + 1, cmp);
s[top = 1] = a[0] = 1;
for (int i = 1;i <= cnt; i++) {
if (a[i] == a[i-1]) continue;
ins(a[i]);
}
while (top > 0) add_e(s[top - 1], s[top]), top--;
}
int main() {
// freopen ("hs.in","r",stdin);
// freopen ("hs.out","w",stdout);
read(n);
for (int i = 1;i < n; i++) {
int x, y; read(x), read(y);
add(x, y); add(y, x);
}
dfs1(1, 0), dfs2(1, 1);
I.col = n + 1, I.ti = n + 1;
for (int i = 1;i <= n; i++) qaq[i] = I;
int ww; read(ww);
while (ww--) {
int k, m; read(m), read(k);
init(m, k), diji();
for (int i = 1;i <= k; i++) printf ("%d ", qaq[ask[i]].col);
putchar('
'); refresh(1, 0);
}
return 0;
}