题目传送门

http://uoj.ac/problem/207

题解

如果是一棵静态的树,有一个非常容易想到的算法:统计一下目前的每一个条边被几条路径经过,如果 \(x\) 到 \(y\) 的边的这个值为 \(|S|\) 的话,那么就是合法的。

但是如果树是动态的,这个算法就有问题了。

link 和 cut 会导致一个点对之间的路径发生改变。


考虑到如果 \(x\) 到 \(y\) 这条边必须要被经过的话,那么就是说覆盖了 \(x\) 到 \(y\) 这条边的路径集恰好是 \(S\)。

回顾 bzoj3569 DZY Loves Chinese II 的做法,把一条路径用同一个 \(int\) 范围内随机的值在路径上的边都异或一边,那么如果两条边的值相同就意味着两条边很有可能是被相同的路径集覆盖。

所以这题也同理,但是因为没有根,所以不能像一般的树一样做树上差分——所以我们直接求子树异或和就可以了。

所以可用维护子树信息的 LCT 维护。


时间复杂度 \(O(m\log n)\)。

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;} typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii; template<typename I> inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
} const int N = 100000 + 7;
const int M = 300000 + 7; #define lc c[0]
#define rc c[1] int n, m, cnt, yz;
int b[M];
pii a[M]; struct Node { int c[2], rev, fa, v, xsum, xs; } t[N];
int st[N];
inline bool idtfy(int o) { return t[t[o].fa].rc == o; }
inline bool isroot(int o) { return t[t[o].fa].lc != o && t[t[o].fa].rc != o; }
inline void connect(int fa, int o, int d) { t[fa].c[d] = o, t[o].fa = fa; }
inline void pushup(int o) { t[o].xsum = t[t[o].lc].xsum ^ t[t[o].rc].xsum ^ t[o].xs ^ t[o].v; }
inline void pushdown(int o) {
if (!t[o].rev) return;
if (t[o].lc) t[t[o].lc].rev ^= 1, std::swap(t[t[o].lc].lc, t[t[o].lc].rc);
if (t[o].rc) t[t[o].rc].rev ^= 1, std::swap(t[t[o].rc].lc, t[t[o].rc].rc);
t[o].rev = 0;
}
inline void rotate(int o) {
int fa = t[o].fa, pa = t[fa].fa, d1 = idtfy(o), d2 = idtfy(fa), b = t[o].c[d1 ^ 1];
if (!isroot(fa)) t[pa].c[d2] = o; t[o].fa = pa;
connect(o, fa, d1 ^ 1), connect(fa, b, d1);
pushup(fa), pushup(o);
}
inline void splay(int o) {
int x = o, tp = 0;
st[++tp] = x;
while (!isroot(x)) st[++tp] = x = t[x].fa;
while (tp) pushdown(st[tp--]);
while (!isroot(o)) {
int fa = t[o].fa;
if (isroot(fa)) rotate(o);
else if (idtfy(o) == idtfy(fa)) rotate(fa), rotate(o);
else rotate(o), rotate(o);
}
}
inline void access(int o) {
for (int x = 0; o; o = t[x = o].fa) {
splay(o);
t[o].xs ^= t[t[o].rc].xsum;
t[o].rc = x;
t[o].xs ^= t[t[o].rc].xsum;
pushup(o);
}
}
inline void mkrt(int o) {
access(o), splay(o);
t[o].rev ^= 1, std::swap(t[o].lc, t[o].rc);
}
inline int getrt(int o) {
access(o), splay(o);
while (pushdown(o), t[o].lc) o = t[o].lc;
return splay(o), o;
}
inline void link(int x, int y) {
mkrt(x);
if (getrt(y) != x) access(y), splay(y), t[x].fa = y, t[y].xs ^= t[x].xsum, pushup(y);
}
inline void cut(int x, int y) {
mkrt(x), access(y), splay(y);
if (t[y].lc == x && !t[x].rc) t[y].lc = t[x].fa = 0, pushup(y);
} inline void work() {
while (m--) {
int opt, x, y, u, v;
read(opt);
if (opt == 1) {
read(x), read(y), read(u), read(v);
cut(x, y), link(u, v);
} else if (opt == 2) {
read(x), read(y);
v = rand(), yz ^= v;
access(x), splay(x), t[x].v ^= v, pushup(x);
access(y), splay(y), t[y].v ^= v, pushup(y);
a[++cnt] = pii(x, y), b[cnt] = v;
} else if (opt == 3) {
read(u);
x = a[u].fi, y = a[u].se, v = b[u], yz ^= v;
access(x), splay(x), t[x].v ^= v, pushup(x);
access(y), splay(y), t[y].v ^= v, pushup(y);
} else if (opt == 4) {
read(x), read(y);
mkrt(x), access(y), splay(x);
assert(t[x].rc == y && !t[y].lc);
// dbg("t[y].xsum = %d, yz = %d, %d, %d\n", t[y].xsum, yz, t[y].v, t[y].xs);
if (t[y].xsum != yz) puts("NO");
else puts("YES");
}
}
} inline void init() {
srand(time(0) + (ull)new char);
read(n), read(n), read(m);
int x, y;
for (int i = 1; i < n; ++i) read(x), read(y), link(x, y);
} int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}

uoj207 共价大爷游长沙 子树信息 LCT + 随机化 + 路径覆盖的更多相关文章

  1. 【LCT维护子树信息】uoj207 共价大爷游长沙

    这道题思路方面就不多讲了,主要是通过这题学一下lct维护子树信息. lct某节点u的子树信息由其重链的一棵splay上信息和若干轻儿子子树信息合并而成. splay是有子树结构的,可以在rotate, ...

  2. [UOJ207]共价大爷游长沙

    UOJ sol 这题真是太神啦! 对于S集合中的每个点对,给他们随机附上一个相同权值. 两个点在边(x,y)的两侧当且仅当一个点在x的子树中,另一个点不在x的子树中(假设x是y的儿子) 维护一下子树点 ...

  3. uoj207共价大爷游长沙

    话说我可能还没有调出魔法森林呢...说好的lct第一题呢... 又是一个随机化的方法,毕竟又是判定性的问题 上次是判断无向图联通 这次是判断一些路径是否经过一条定边 若把路径上的边全部异或上一个路径的 ...

  4. UOJ #207. 共价大爷游长沙 [lct 异或]

    #207. 共价大爷游长沙 题意:一棵树,支持加边删边,加入点对,删除点对,询问所有点对是否经过一条边 一开始一直想在边权上做文章,或者从连通分量角度考虑,比较接近正解了,但是没想到给点对分配权值所以 ...

  5. 【UOJ207】共价大爷游长沙(Link-Cut Tree,随机化)

    [UOJ207]共价大爷游长沙(Link-Cut Tree,随机化) 题面 UOJ 题解 这题太神了 \(\%\%\%myy\) 看到动态的维护边很容易的想到了\(LCT\) 然后能否堵住一条路 我们 ...

  6. 「UOJ207」共价大爷游长沙

    「UOJ207」共价大爷游长沙 解题思路 : 快速判断两个集合是否完全相等可以随机点权 \(\text{xor}\) 的思路可以用到这道题上面,给每一条路径随机一个点权,维护出经过每一条边的点权的 \ ...

  7. 【刷题】UOJ #207 共价大爷游长沙

    火车司机出秦川,跳蚤国王下江南,共价大爷游长沙.每个周末,勤劳的共价大爷都会开车游历长沙市. 长沙市的交通线路可以抽象成为一个 \(n\) 个点 \(n−1\) 条边的无向图,点编号为 \(1\) 到 ...

  8. UOJ #207. 共价大爷游长沙

    #207. 共价大爷游长沙 链接:http://uoj.ac/problem/207 题意:给一棵树,要求支持加边.删边.询问一条边是否被所有路径覆盖.同时路径端点集合有加入与删除操作. 想法: 考虑 ...

  9. 【UOJ#207】共价大爷游长沙

    题目链接 题目描述 火车司机出秦川,跳蚤国王下江南,共价大爷游长沙.每个周末,勤劳的共价大爷都会开车游历长沙市. 长沙市的交通线路可以抽象成为一个 \(n\) 个点 \(n−1\) 条边的无向图,点编 ...

随机推荐

  1. 阶段3 1.Mybatis_05.使用Mybatis完成CRUD_7 Mybatis中参数的深入-使用实体类的包装对象作为查询条件

    pojo对象就是实体类 综合查询-实体类包装起来做查询 新建实体类QueryVo 提供一个User对象属性,并生成getter和setter 测试 修改dao接口中的返回类型为List<User ...

  2. Linux监控命令之==>free

    一.命令说明 free 命令显示系统内存的使用情况:包括物理内存.交换内存(swap)和内核缓冲区内存 二.参数说明 -b -k -m -g:分别以字节.KB.MB.GB为单位显示内存使用情况 -l: ...

  3. C 语言的函数 - 内存分析

    函数基本概念 Linux 中,函数在内存的代码段(code 区),地址比较靠前. 函数定义 C 语言中,函数有三个要素:入参.返回值.函数名,缺一不可.函数使用前必须先声明,或者在使用之前定义. 函数 ...

  4. 在Vue文件中引入外部URL链接

    前言:最近做一个vueNuxt的项,没有index.html 也没有main.js项目需要引入一些外部的包,没什么技术含量只是一种思路 在vue生命钩子函数中动态创建JavaScript标签追加到HT ...

  5. SpringCloud:(一)服务注册与发现

    最近跟着方志明老师学习SpringCloud,博客地址如下: https://blog.csdn.net/forezp/article/details/81040925 自己也跟着撸了一遍,纸上得来终 ...

  6. WEB框架实战总结

    Django 在新一代的 Web框架 中非常出色 使用Python开发Web,最简单,原始和直接的办法是使用CGI标准,可以用WSGI接口 一.WSGI接口实现web页面 运行WSGI服务 我们先编写 ...

  7. jmeter遍历时间戳

    list如下 实现步骤 实现步骤其实很简单,只需要一个foreach控制器,和一段转换时间戳的代码 第一步把时间戳提取出来 第二步把提取的时间戳传入foreach控制器,然后在控制器下面遍历转换 im ...

  8. ionic3构建过程中遇到的找不到AndroidManifest.xml的问题

    问题如下: Failed to install 'ionic-plugin-keyboard': Error: ENOENT: no such file or directory, open '/Us ...

  9. kettle入门大数据管理工具

    研究 kettle 的使用 大佬博客:https://www.cnblogs.com/mq0036/p/9238646.html 国内镜像下载:http://mirror.bit.edu.cn/pen ...

  10. 携程的 Dubbo 之路,值得学习!

    注:本篇文章整理自董艺荃在 Dubbo 社区开发者日上海站的演讲. 1.缘起 携程当初为什么要引入 Dubbo 呢?实际上从 2013 年底起,携程内主要使用的就是基于 HTTP 协议的 SOA 微服 ...