题目链接

题目

题目描述

树国是一个有n个城市的国家,城市编号为1∼n。连接这些城市的道路网络形如一棵树,

即任意两个城市之间有恰好一条路径。城市中有k个帮派,编号为1∼k。每个帮派会占据一些城市,以进行非法交易。有时帮派之间会结盟,这就使得城市更加不安全了。同一座城市中可能有多个帮派。

当一些帮派结成联盟时,他们会更加强大,同时也更加危险。他们所控制的城市数会显著增加。具体地,一个联盟控制的城市是联盟中所有帮派所占据的城市,再加上这些城市两两之间路径上的所有城市。

shy是树国的市长,他想要选择一个城市作为首都。在决定之前,他要先做一些调研。为此,他找来你帮他回答一些询问,你能做到吗?在每个询问中,shy会选择一个城市作为首都,同时会告诉你当前活跃的帮派的集合。在这个询问中,你只需要考虑给定的集合中的帮派,其他的帮派你可以当作不存在。已知给定集合中的这些帮派结成了联盟,shy希望抓获联盟中的人,以得到关于整个联盟的一些信息。为此,他要找到被联盟控制的所有城市中离首都最近的一座城市到首都的距离。有可能首都本身就被控制了,此时答案为0。请注意,询问之间相互独立,互不影响。

输入描述

输入的第一行包含一个整数n,代表树国中的城市数。

接下来n−1行,每行包含两个整数u和v,代表城市u和v之间存在一条道路。

接下来一行包含一个整数k,代表树国中的帮派数。

接下来k行,每行描述一个帮派。第i行的第一个整数c[i]代表第i个帮派占据的城市数,接下来c[i]个整数,代表被第i个帮派占据的城市。

接下来一行包含一个整数Q,代表询问数。

接下来Q行,每行描述一个询问。每行的前两个整数V和t[i]代表本次询问中的首都与需要考虑的帮派集合的大小。接下来t[i]个整数代表本次询问中需要考虑的帮派。.

输出描述

对于每个询问,输出一行,包含一个整数,代表询问的答案。

示例1

输入

7
1 2
1 3
2 4
2 5
3 6
3 7
2
2 6 7
1 4
3
5 1 2
1 1 1
5 2 1 2

输出

2
1
1

备注

对于30%的数据,1≤n,k,Q≤1000, 1≤每个帮派占据城市数之和≤1000, 1≤每个询问中考虑的帮派数之和≤1000 对于60%的数据,1≤n,k,Q≤100000, 1≤每个帮派占据城市数之和≤100000, 1≤每个询问中考虑的帮派数之和≤100000 对于100%的数据,1≤n,k,Q≤500000, 1≤每个帮派占据城市数之和≤500000, 1≤每个询问中考虑的帮派数之和≤500000

题解

知识点:DFS序,LCA。

考虑一次询问的 \(t_i\) 个帮派的联盟,设它们城市的LCA为 \(lca\) 分类讨论:

  1. \(LCA(lca,x) \neq lca\) 时,说明 \(x\) 一定不会在这个联盟,答案是 \(dist(lca,x)\) 。
  2. \(LCA(lca,x) = lca\) 时,说明 \(x\) 在联盟LCA的子树里,可能会在被占据城市的路径上。此时,我们需要先得到离 \(x\) 最近的被占据城市 \(id\) ,计算 \(x\) 到 \(LCA(x,id)\) 的距离,即 \(x\) 到最近一条路径上的城市的距离。这是因为, \(LCA(x,id)\) 在 \(x\) 到 \(lca\) 的路径上,因此一定在某条占据城市的路径上,且这是距离 \(x\) 最近的一个城市。

其中,关于求出某个帮派最近的一个被占据的城市,记录帮派城市的dfn序列并排序,找出在排序后的序列里,离 \(x\) dfn序左右最近的两个城市即可,可以通过二分查找。

另外,我们可以事先求出每个帮派占据城市的LCA,在多次询问中可以节省时间。

时间复杂度 \(O(n\log n+\sum c_i + \sum t_i \log c_{q_i})\)

空间复杂度 \(O(n \log n + \sum c_i)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; struct Graph {
struct edge {
int v, nxt;
};
int idx;
vector<int> h;
vector<edge> e; Graph(int n = 0, int m = 0) { init(n, m); } void init(int n, int m) {
idx = 0;
h.assign(n + 1, 0);
e.assign(m + 1, {});
} void add(int u, int v) {
e[++idx] = { v,h[u] };
h[u] = idx;
}
}; template<class T>
struct ST {
vector<vector<T>> node; public:
ST() {}
ST(const vector<T> &src) { init(src); } void init(const vector<T> &src) {
assert(src.size());
int n = src.size() - 1;
int sz = log2(n);
node.assign(sz + 1, vector<T>(n + 1));
for (int i = 1;i <= n;i++) node[0][i] = src[i];
for (int i = 1;i <= sz;i++)
for (int j = 1;j + (1 << i) - 1 <= n;j++)
node[i][j] = node[i - 1][j] + node[i - 1][j + (1 << i - 1)];
} T query(int l, int r) {
int k = log2(r - l + 1);
return node[k][l] + node[k][r - (1 << k) + 1];
}
}; const int N = 500007;
Graph g; int dfncnt, eulcnt;
int dfn[N], pos[N], eul[N << 1], dep[N];//! euler序列要两倍
void dfs(int u, int fa) {
dfn[++dfncnt] = u;
eul[++eulcnt] = u;
pos[u] = eulcnt;
dep[u] = dep[fa] + 1;
for (int i = g.h[u];i;i = g.e[i].nxt) {
int v = g.e[i].v;
if (fa == v) continue;
dfs(v, u);
eul[++eulcnt] = eul[pos[u]];
}
} struct T {
int mi;
friend T operator+(const T &a, const T &b) { return { dep[a.mi] < dep[b.mi] ? a.mi : b.mi }; }
}; ST<T> st;
int LCA(int u, int v) {
u = pos[u], v = pos[v];
if (u > v) swap(u, v);
return st.query(u, v).mi;
} int dis(int u, int v) { return dep[u] + dep[v] - 2 * dep[LCA(u, v)]; } int c[N];
int c_lca[N];
vector<int> c_id[N];
int Q[N]; int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
g.init(n, n << 1);
for (int i = 1;i <= n - 1;i++) {
int u, v;
cin >> u >> v;
g.add(u, v);
g.add(v, u);
} dfs(1, 0);
vector<T> eul_src(eulcnt + 1);
for (int i = 1;i <= eulcnt;i++) eul_src[i] = { eul[i] };
st.init(eul_src); auto f = [&](int a, int b) {return pos[a] < pos[b];}; int k;
cin >> k;
for (int i = 1;i <= k;i++) {
cin >> c[i];
for (int j = 1;j <= c[i];j++) {
int x;
cin >> x;
c_id[i].push_back(x);
c_lca[i] = j == 1 ? x : LCA(c_lca[i], x);
}
sort(c_id[i].begin(), c_id[i].end(), f);
} int q;
cin >> q;
while (q--) {
int x, t;
cin >> x >> t;
int lca;
for (int i = 1;i <= t;i++) {
cin >> Q[i];
lca = i == 1 ? c_lca[Q[i]] : LCA(lca, c_lca[Q[i]]);
}
if (LCA(x, lca) != lca) cout << dis(x, lca) << '\n';
else {
int ans = 1e9;
for (int i = 1;i <= t;i++) {
int id = lower_bound(c_id[Q[i]].begin(), c_id[Q[i]].end(), x, f) - c_id[Q[i]].begin();
if (id < c_id[Q[i]].size())ans = min(ans, dis(x, LCA(x, c_id[Q[i]][id])));
if (id > 0) ans = min(ans, dis(x, LCA(x, c_id[Q[i]][id - 1])));
}
cout << ans << '\n';
}
}
return 0;
}

NC13950 Alliances的更多相关文章

  1. Wannafly模拟赛2 C alliances(dfs序+二分)

    题目 https://www.nowcoder.com/acm/contest/4/C 题意 由n个点组成一个树,有m个帮派,每个帮派由一些个点组成,这些点以及它们两两路径上的所有点都属于该帮派的管辖 ...

  2. Alliances

    树国是一个有n个城市的国家,城市编号为1∼n.连接这些城市的道路网络形如一棵树, 即任意两个城市之间有恰好一条路径.城市中有k个帮派,编号为1∼k.每个帮派会占据一些城市,以进行非法交易.有时帮派之间 ...

  3. 牛客 4C Alliances (dfs序)

    大意: 给定树, 有$k$个帮派, 第$i$个帮派所占据点为$c_i$, 以及$c_i$两两相连路径上的所有点. 一个点可能被多个帮派占领. $q$个询问, 第$i$个询问给定$t_i$个帮派, 给定 ...

  4. #英文#品读中国城市个性——最好的和最坏的&当东方遇到西方

    冒险家的乐园 a playground of risk 实现发财梦 realize one's dreams of wealth 道德沦丧,堕落 moral deprivation 租界 foreig ...

  5. 魔兽争霸3 replay 格式

    ******************************************************************************* * WarCraft III Repla ...

  6. The Sorrows of Young Werther

    The Sorrows of Young Werther J.W. von Goethe Thomas Carlyle and R.D. Boylan Edited by Nathen Haskell ...

  7. Python统计词频的几种方式

    语料 text = """My fellow citizens: I stand here today humbled by the task before us, gr ...

  8. List of regional organizations by population

    https://baike.baidu.com/item/国际组织/261053?fr=aladdin 经济文化类组织(非政府组织) 创行 狮子会 全球青年领导力联盟 乐施会 政治类组织 欧洲联盟(欧 ...

  9. 奥巴马(Obama)获胜演讲全文[中英对照]+高清视频下载

    http://www.amznz.com/obama-speech/如果还有人对美国是否凡事都有可能存疑,还有人怀疑美国奠基者的梦想在我们所处的时代是否依然鲜活,还有人质疑我们的民主制度的力量,那么今 ...

  10. Distributed Management Task Force----分布式管理任务组

    http://baike.baidu.com/link?url=Y9HGLs8Qj6pXbbgY6xPdfiGDsQO8Eu1e80B4giQtQ_hAfGNF59byxnLoERYri4Duw7Gw ...

随机推荐

  1. springboot启动流程 (1) 流程概览

    本文将通过阅读源码方式分析SpringBoot应用的启动流程,不涉及Spring启动部分(有相应的文章介绍). 本文不会对各个流程做展开分析,后续会有文章介绍详细流程. SpringApplicati ...

  2. [转帖]JVM系列之:再谈java中的safepoint

    https://zhuanlan.zhihu.com/p/171625395 safepoint是什么 java程序里面有很多很多的java线程,每个java线程又有自己的stack,并且共享了hea ...

  3. [转帖]TiKV集群搭建

    https://www.cnblogs.com/luohaixian/p/15227788.html 1.准备环境 准备4台ubuntu 16.04虚拟机 部署规划: 节点类型 CPU 内存 存储 部 ...

  4. [转帖]vdbench - 性能压力测试工具

    <存储工具系列文章>主要介绍存储相关的测试和调试工具,包括不限于dd.fio.vdbench.iozone.iometer.cosbench等性能负载工具,及strace等调试工具. 1. ...

  5. [转帖]linux删除文本文件空白行

    linux删除文本文件空白行https://www.zhihu.com/people/chen-kai-84-54-75 sed命令 在Linux中,可以使用sed命令批量删除文本中的空白行.以下是一 ...

  6. Grafana监控java应用以及vCenter的方法

    Grafana监控java应用以及vCenter的方法 背景 最开始弄过vCenter的监控. 但是发现很多地方已经不合适了. 今天看了下jmx监控 java的应用. 顺便监控了下vCenter. 这 ...

  7. redis 6源码解析之 dict

    edis源码的dict.c主要实现了基于hash表的操作,如增删改查,对哈希表大小的扩容和缩容,以及对哈希表的rehash和增量rehash等.在源码的dictScan函数中,非常巧妙精美地实现了对哈 ...

  8. git有关commit的命令

    2.更改最近一次(本次) commit 的提交信息: 当我们执行 git add . git commit -m "0-0-1" 之后我们发现自己写的提交信息是不符合项目要求的,这 ...

  9. Typescript中存取器getters和setters的使用

    1.存取器 存取器可以让我们可以有效的控制对,对象中的中的成员的访问. 可以通过getters和setters来进行操作 在typescript中分别对应 get 和 set 2.如何解决报错 typ ...

  10. 对象数组,如果key中的value相同,不要该项

    <script type="text/javascript"> let arr=[ { gradeId: "498094709437239572", ...