[IOI2018] werewolf 狼人

LG传送门

kruskal重构树好题。

日常安利博客文章

这题需要搞两棵重构树出来,这两棵重构树和我们平时见过的重构树有点不同(据说叫做点权重构树?),根据经过我们简化的建树方法,这两棵树不再是二叉树,但是仍具有kruskal重构树的优秀性质,建议结合后面的描述理解。

看这题需要首先我们从\(S\)走到\(T\)转化为分别从\(S\)和\(T\)出发寻找能共同到达的点,需要快速求出从某个点出发经过点权不大(小)于\(r\)(\(l\))的点,考虑kruskal重构树。令每条边的的边权为所连接两点的较大(小)值,造两棵重构树,这样就可以像平时一样直接倍增做了,但是我们发现边权的信息实际上就是点权的信息,于是我们在建新树时就不另建新点了,这就是所谓的“点权重构树”。建出树处理倍增之后,我们的问题就变成了查询两棵树上两棵子树是否有交,用dfs序表达就是一个简单的二维数点的问题,直接主席树。

#include <cstdio>
#include <cctype>
#include <vector>
#define R register
#define I inline
#define B 1000000
using namespace std;
const int N = 200003;
char buf[B], *p1, *p2;
I char gc() { return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, B, stdin), p1==p2) ? EOF : *p1++; }
I int rd() {
R int f = 0;
R char c = gc();
while (c < 48 || c > 57) c = gc();
while (c > 47 && c < 58) f = f * 10 + (c ^ 48), c = gc();
return f;
}
int s[N], rt[N], val[N], T;
vector <int> g[N];
struct edge { int g, s; };
struct segtree { int p, q, s; }e[N << 5];
struct kruskal {
int h[N], f[N], fa[N][20], dfn[N], low[N], E, tim;
edge e[N];
I void add(int x, int y) { e[++E] = (edge){y, h[x]}, h[x] = E; }
I int find(int x) {
R int r = x, y;
while (f[r] ^ r)
r = f[r];
while (x ^ r)
y = f[x], f[x] = r, x = y;
return r;
}
void dfs(int x) {
dfn[x] = ++tim;
R int i;
for (i = 1; i < 20; ++i)
fa[x][i] = fa[fa[x][i - 1]][i - 1];
for (i = h[x]; i; i = e[i].s)
dfs(e[i].g);
low[x] = tim;
}
}X, Y;
int modify(int k, int l, int r, int x) {
R int t = ++T;
e[t].p = e[k].p, e[t].q = e[k].q, e[t].s = e[k].s + 1;
if (l == r)
return t;
R int m = l + r >> 1;
if (x <= m)
e[t].p = modify(e[k].p, l, m, x);
else
e[t].q = modify(e[k].q, m + 1, r, x);
return t;
}
int query(int k, int t, int l, int r, int x, int y) {
if (x <= l && r <= y)
return e[t].s - e[k].s;
R int m = l + r >> 1, o = 0;
if (x <= m)
o += query(e[k].p, e[t].p, l, m, x, y);
if (m < y)
o += query(e[k].q, e[t].q, m + 1, r, x, y);
return o;
}
int main() {
R int n = rd(), m = rd(), Q = rd(), i, x, y, l, r;
for (i = 1; i <= m; ++i)
x = rd() + 1, y = rd() + 1, g[x].push_back(y), g[y].push_back(x);
for (i = 1; i <= n; ++i)
X.f[i] = i, Y.f[i] = i, s[i] = g[i].size();
for (x = n; x; --x)
for (i = 0; i < s[x]; ++i)
if (g[x][i] > x && (y = X.find(g[x][i])) ^ x)
X.add(x, y), X.f[y] = X.fa[y][0] = x;
for (x = 1; x <= n; ++x)
for (i = 0; i < s[x]; ++i)
if (g[x][i] < x && (y = Y.find(g[x][i])) ^ x)
Y.add(x, y), Y.f[y] = Y.fa[y][0] = x;
X.dfs(1), Y.dfs(n);
for (i = 1; i <= n; ++i)
val[X.dfn[i]] = Y.dfn[i];
for (i = 1; i <= n; ++i)
rt[i] = modify(rt[i - 1], 1, n, val[i]);
while (Q--) {
x = rd() + 1, y = rd() + 1, l = rd() + 1, r = rd() + 1;
for (i = 19; ~i; --i)
if (X.fa[x][i] >= l)
x = X.fa[x][i];
for (i = 19; ~i; --i)
if (Y.fa[y][i] && Y.fa[y][i] <= r)
y = Y.fa[y][i];
printf(query(rt[X.dfn[x] - 1], rt[X.low[x]], 1, n, Y.dfn[y], Y.low[y]) ? "1\n" : "0\n");
}
return 0;
}

[IOI2018] werewolf 狼人 kruskal重构树,主席树的更多相关文章

  1. [IOI2018] werewolf 狼人 [kruskal重构树+主席树]

    题意: 当你是人形的时候你只能走 \([L,N-1]\) 的编号的点(即大于等于L的点) 当你是狼形的时候你只能走 \([1,R]\) 的编号的点(即小于等于R的点) 然后问题转化成人形和狼形能到的点 ...

  2. LOJ.2865.[IOI2018]狼人(Kruskal重构树 主席树)

    LOJ 洛谷 这题不就是Peaks(加强版)或者归程么..这算是\(IOI2018\)撞上\(NOI2018\)的题了? \(Kruskal\)重构树(具体是所有点按从小到大/从大到小的顺序,依次加入 ...

  3. luoguP4197:Peaks(Kruskal重构树+主席树)或者(点分树+离线)

    题意:有N座山,M条道路.山有山高,路有困难值(即点权和边权).现在Q次询问,每次给出(v,p),让求从v出发,只能结果边权<=p的边,问能够到达的山中,第K高的高度(从大到小排序). 思路:显 ...

  4. UOJ#407. 【IOI2018】狼人 Kruskal,kruskal重构树,主席树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ407.html 题解 套路啊. 先按照两个节点顺序各搞一个kruskal重构树,然后问题转化成两棵krus ...

  5. 【BZOJ-3545&3551】Peaks&加强版 Kruskal重构树 + 主席树 + DFS序 + 倍增

    3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1202  Solved: 321[Submit][Sta ...

  6. BZOJ3545&3551[ONTAK2010]Peaks——kruskal重构树+主席树+dfs序+树上倍增

    题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只 ...

  7. luogu4197 Peaks (kruskal重构树+主席树)

    按照边权排序建出kruskal重构树,每次就变成了先找一个权值<=x的最远的祖先,然后看这个子树的第k小.离散化一下,在dfs序上做主席树即可 而且只需要建叶节点的主席树 注意输出的是第k小点的 ...

  8. 洛谷P4197 Peaks(Kruskal重构树 主席树)

    题意 题目链接 往后中文题就不翻译了qwq Sol 又是码农题..出题人这是强行把Kruskal重构树和主席树拼一块了啊.. 首先由于给出的限制条件是<=x,因此我们在最小生成树上走一定是最优的 ...

  9. [BZOJ3551][ONTAK2010]Peaks(加强版)(Kruskal重构树,主席树)

    3551: [ONTAK2010]Peaks加强版 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2438  Solved: 763[Submit][ ...

随机推荐

  1. MongoDB 安装和使用问题总结

    1. 一直安装不了[一直next下去但最后没有发现生成文件夹] 去掉 Installing MongoDB Compass 前面的打勾 2. 需要开两个cmd运行mongodb 开第一个,输入以下运行 ...

  2. [转]Centos7下面配置静态IP

    修改网卡配置文件(操作前先备份一下该文件),/etc/sysconfig/network-scripts/ifcfg-enp0s3 ,如下: TYPE=Ethernet BOOTPROTO=stati ...

  3. 铁乐学python_day13_迭代器生成器

    一.[可迭代对象Iterable] 粗略判断的话,我们可以说能被for循环进行遍历的对象就是可迭代对象,如str,list,tuple,dict(key),set,range. (open file ...

  4. Laravel 实践之路: 数据库迁移与数据填充

    数据库迁移实际上就是对数据库库表的结构变化做版本控制,之前对数据库库表结构做修改的方式比较原始,比如说对某张库表新增了一个字段,都是直接在库表中执行alter table xxx add .. 的方式 ...

  5. 安装zabbix3.4的过程(一)

    目录 zabbix服务端安装(centos7.4) zabbix客户端安装 (centos6.9) 注释:本次安装为官方推荐的yum安装方式,如果需要编译安装,请查看下边的博文: 博文地址:https ...

  6. IP地址编址

    比特:一比特就是一个数字,1或者0. 字节:以字节是7比特或者8比特,取决于是否使用奇偶校验 八位组:8比特构成 网络地址:用来将数据包发送到远端网路 比如10.0.0.0 广播地址:将信息发送给网络 ...

  7. Programming Assignment 2: Deques and Randomized Queues

    编程作业二 作业链接:Deques and Randomized Queues & Checklist 我的代码:Deque.java & RandomizedQueue.java & ...

  8. BZOJ 1066 蜥蜴 最大流

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1066 题目大意: 在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥 ...

  9. 1026. [SCOI2009]windy数【数位DP】

    Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道, 在A和B之间,包括A和B,总共有多少个windy数? I ...

  10. [luogu2680] 运输计划

    题面 ​ 很明显, 由于是求最长路的最小值, 我们可以使用二分求解. 我们二分一个长度\(mid\), 将所有使得\(dis(u, v)\)大于\(mid\)的点对\((u, v)\)找出, 设总共有 ...