【2017.10.21】NOIP赛前集训 | T1找位置 【最短路 + dfs】、T2 砍树枝【倍增 / dfs序】、T3 搬砖【倍增】
目录
【问题描述】
Farmer John 想找一个最好的位置来建新农场,这样他每天可以少走些路。
FJ 所在的区域,有 N 个城镇(1 <= N <= 10,000)。
城镇之间,有 M(1 <= M <= 50,000)条双向路相连。
所有城镇都可以借助一些路相互连接。
FJ 需要你的帮助来选择最合适建新农场的城镇。
K(1 <= K <= 5)个城镇中有超市,FJ 每天都会去这些超市。
他计划每天从新农场出发,访问包含超市的 K 个城镇,然后返回新农场。
FJ 可以按照任意的顺序访问这些超市。 FJ 只会在 N-K 个城镇中,选择一个城镇来建新农场。因为其他城镇的房 价,比较低一些。
如果他把农场建在最优的位置,而且尽可能明智的选择行走路线。
请帮 FJ 计算,他每天需要行走的最短路线长度。 当然,一个城镇可以经过多次。
【输入】
第 1 行:三个空格隔开的整数,N,M 和 K。
第 2..1+K 行:第 i+1 行包含一个整数,范围 1..N,表示包含第 i 个超市 的城镇。
每个超市在不同城镇。
第 2+K..1+K+M 行:每行包含三个空格隔开的整数,i,j(1 <= i,j <= N), 和 L(1 <= L <= 1000), 表示城镇 i 和城镇 j 之间存在一条长度为 L 的路。
【输出】
如果他把农场建在最优的位置,FJ 每天需要行走的最短路线长度。
【输入输出样例】
in
5 6 3
1
2
3
1 2 1
1 5 2
3 2 3
3 4 5
4 2 7
4 5 10
out
12
【样例解释】
FJ 在 5 号城镇建立农场。他每天的行走路线为 5-1-2-3-2-1-5,路线长度 为 12
首先跑 k 遍 Dijkstra \ spfa \ ...,求出每个超市到其他城镇的最短路。然后枚举农夫将农场建在了哪个城镇中(就是没有超市的城镇,共 n-k 个)。
再 dfs 检查 每一个可能的日程表(k 个有超市的城镇的全排列,一共 k!个),记录最短的路线,在所有答案中记录最优答案。
【问题描述】
这天,CD 作为 moreD 的宠物,又被残酷地训练爬树了,moreD 保证了这棵 树满足从任意一个点出发,CD 都能走到所有的点,CD 每天都要爬过所有的点才 能回家吃饭。经过一天又一天残酷的训练以后,CD 已经忍无可忍了,于是 CD 会愤怒地误伤一条树枝,一条树枝被误伤以后就不可以再走了。
当然,CD 不符合宠物法则的行动怎么会逃过 moreD 的眼睛,moreD 决定, 每当 CD 误伤一条树枝,他都会再重新加一条树枝,可是他不知道加完以后,这 只宠物是否还能从任意一个点出发到达所有的点,要是不能,岂不是让这只宠 物得逞了么?
问题是,现在 moreD 也不知道 CD 最终会误伤哪一条树枝,于是现在 moreD 臆测出了许多种可能,你要告诉 moreD:如果 CD 误伤了第 z 条边,他再在编号 为 x 的点和编号为 y 的点之间加一条边,CD 是否能得逞。
【输入格式】
第一行一个正整数 n,表示节点个数。 接下来 n-1 行,每行两个正整数 x,y,表示原来树上存在一条连接编号为 x 的节点和编号为 y 的节点的边。 第 n+1 行一个正整数 Q,表示询问次数。 接下来 Q 行,每行三个正整数 x,y,z,表示一个询问(含义如题所示)。
【输出格式】
输出共 Q 行。 对于每一个询问,如果 CD 会得逞就输出 YES,否则输出 NO。
【样例输入输出】
5
1 2
2 3
2 4
4 5
3
2 5 3
2 3 1
1 5 2
NO
YES
YES
【数据说明】
对于 20%的数据保证 n,Q≤1000。
对于另外 20%的数据保证 n,Q≤10000 且树为随机生成。
对于 70%的数据保证 n,Q≤200000。 对
于 100%的数据保证 n≤200000,Q≤2000000。
- 20% - 并查集倒序离线操作
View Code#include <cstdio> const int MAXN = 200000 + 7; int dad[MAXN], n, q, edge[MAXN][3]; int getdad(int x) { return dad[x] == x ? x : getdad(dad[x]); } void Union(int x, int y) { int u = getdad(x), v = getdad(y); if (u != v) { dad[v] = u; // printf("dad[%d] = %d\n", v, u); for (int i = 1; i <= n; i++) if (dad[i] == v) dad[i] = u; //printf("dad[%d] = %d\n", i, u), } } int main() { freopen("tree.in", "r", stdin); freopen("tree.out", "w", stdout); scanf("%d", &n); for (int i = 1; i < n; i++) scanf("%d%d", &edge[i][1], &edge[i][2]); scanf("%d", &q); while (q--) { for (int i =1; i <= n; i++) dad[i] = i; int x, y, z; scanf("%d%d%d", &x, &y, &z); for (int i = 1; i < n; i++) { if (i == z) continue; int u = getdad(edge[i][1]), v = getdad(edge[i][2]); // printf("dad[%d] = %d \n", v, u); Union(u, v); } Union(x, y); for (int i = 1; i <= n; i++) printf("%d ", dad[i]); printf("\n"); bool flag = 1; int bierenjiadehaizi = dad[1]; for (int i = 1; i <= n; i++) if (dad[i] != bierenjiadehaizi) flag = 0; printf(flag ? "NO\n" : "YES\n"); } return 0; }
我不会告诉你 moreD 神犇最喜欢搬砖了。 砖,当然是指魔砖,魔法砖带有一个魔法标记,只能摆在区间[Li,Ri]里。 正所谓日久生情,moreD 对砖头的热爱已经到了一个忘我的境界,他认为砖 头也是有生命的,他希望各个砖可以和睦相处。具体来说是砖头越多越好。 moreD 每一次选定一个区间,然后选定一些砖头放入。使得这些砖头互不重 叠,且任意选定的砖头的魔法标记不超出 moreD 选定的区间。 对于 moreD 每一次选定的区间,你需要回答 moreD,他最多可放入多少砖头 哦。
【输入格式】
第一行三个整数 N,Q,len,表示砖头的数量,询问数和 len 的大小,1≤ Li,Ri≤len。 接下来 N 行,每行两个整数 Li,Ri,表示砖头的魔法标记。 接下来 Q 行,每行两个整数 pi,qi,表示 moreD 选定的区间。
【输出格式】
对于每组询问输出对应的答案。
【输入样例】
3 2 4
1 2
2 3
3 4
1 3
3 3
【输出样例】
1
0
【数据范围】
对于 30%的数据满足 N≤10,Q≤10
对于 60%的数据满足 N≤1,000,Q≤1,000 1≤Li,Ri≤1,000
对于 100%的数据满足 N≤100,000,Q≤100,000 1≤Li,Ri≤len≤100,000


浙公网安备 33010602011771号