【刷题】UOJ #207 共价大爷游长沙
火车司机出秦川,跳蚤国王下江南,共价大爷游长沙。每个周末,勤劳的共价大爷都会开车游历长沙市。
长沙市的交通线路可以抽象成为一个 \(n\) 个点 \(n−1\) 条边的无向图,点编号为 \(1\) 到 \(n\),任意两点间均存在恰好一条路径,显然两个点之间最多也只会有一条边相连。有一个包含一些点对 \((x,y)\) 的可重集合S,共价大爷的旅行路线是这样确定的:每次他会选择 \(S\) 中的某一对点 \((x,y)\),并从 \(x\) 出发沿着唯一路径到达 \(y\) 。
小L是共价大爷的脑残粉,为了见到共价大爷的尊容,小L决定守在这张图的某条边上等待共价大爷的到来。为了保证一定能见到他,显然小L必须选择共价大爷一定会经过的边——也就是所有共价大爷可能选择的路径都经过的边。
现在小L想知道,如果他守在某一条边,是否一定能见到共价大爷。
然而长沙市总是不断的施工,也就是说,可能某个时刻某条边会断开,同时这个时刻一定也有某条新边会出现,且任意时刻图都满足任意两点间均存在恰好一条路径的条件。 注意断开的边有可能和加入的新边连接着相同的两个端点。共价大爷的兴趣也会不断变化,所以S也会不断加入新点对或者删除原有的点对。 当然,小L也有可能在任何时候向你提出守在某一条边是否一定能见到共价大爷的问题。你能回答小L的所有问题吗?
输入格式
输入的第一行包含一个整数 \(id\),表示测试数据编号,如第一组数据的\(id=1\),样例数据的 \(id\) 可以忽略。hack数据中的 \(id\) 必须为 \(0\) 到 \(10\) 之间的整数。hack数据中 \(id\) 的值和数据类型没有任何关系。
输入的第二行包含两个整数 \(n,m\),分别表示图中的点数,以及接下来会发生的事件数,事件的定义下文中会有描述。初始时 \(S\) 为空。
接下来 \(n−1\) 行,每行两个正整数 \(x,y\),表示点 \(x\) 和点 \(y\) 之间有一条无向边。
接下来 \(m\) 行,每行描述一个事件,每行的第一个数 \(type\) 表示事件的类型。
若 \(type=1\),那么接下来有四个正整数 \(x,y,u,v\),表示先删除连接点 \(x\) 和点 \(y\) 的无向边,保证存在这样的无向边,然后加入一条连接点 \(u\) 和点 \(v\) 的无向边,保证操作后的图仍然满足题中所述条件。
若 \(type=2\),那么接下来有两个正整数 \(x,y\),表示在 \(S\) 中加入点对 \((x,y)\) 。
若 \(type=3\),那么接下来有一个正整数 \(x\),表示删除第 \(x\) 个加入 \(S\) 中的点对,即在第 \(x\) 个 \(type=2\) 的事件中加入 \(S\) 中的点对,保证这个点对存在且仍然在 \(S\) 中。
若 \(type=4\),那么接下来有两个正整数 \(x,y\),表示小L询问守在连接点 \(x\) 和点 \(y\) 的边上是否一定能见到共价大爷,保证存在这样的无向边且此时 \(S\) 不为空。
输出格式
对于每个小L的询问,输出“YES”或者“NO”(均不含引号)表示小L一定能或者不一定能见到共价大爷。
样例一
input
0
5 7
1 2
1 3
2 4
1 5
2 1 5
1 1 5 2 5
4 2 5
2 1 4
4 2 5
3 1
4 2 4
output
YES
NO
YES
explanation
最开始将点对 \((1,5)\) 加入到 \(S\) 中,此时点 \(1\) 和点 \(5\) 之间的路径是 \(1→5\)。
接着将连接点 \(1\) 和点 \(5\) 的边断开,加入连接点 \(2\) 和点 \(5\) 的边,我们发现图仍然满足题中所述条件,且点 \(1\) 和点 \(5\) 之间的路径是 \(1→2→5\),经过点了 \(2\) 和点 \(5\) 之间的边,因此第一个询问答案是 YES。
接着将点对 \((1,4)\) 加入到 \(S\) 中,点 \(1\) 和点 \(4\) 之间的路径是 \(1→2→4\),没有经过点 \(2\) 和点 \(5\) 之间的边,因此第二个询问答案是 NO。
接着,我们删除了第一个加入到 \(S\) 中的点对,也就是点对 \((1,5)\),此时 \(S\) 中唯一的点对就是 \((1,4)\),经过了点 \(2\) 和点 \(4\) 之间的边,因此最后一个询问答案是 YES。
样例二
见样例数据下载。
样例三
见样例数据下载。这组数据中 \(type≠1\)。
限制与约定
每组测试数据的限制与约定如下所示:
测试点编号 | $n$ | $m$ | $type=$ | 限制与约定 |
$1$ | $n≤100$ | $m≤100$ | $1,2,3,4$ | |
$2$ | $n≤100000$ | $m≤300000$ | $2,4$ | |
$3$ | ||||
$4$ | $2,3,4$ | |||
$5$ | ||||
$6$ | $1,2,3,4$ | 任意时刻 $|S|≤10$ | ||
$7$ | ||||
$8$ | ||||
$9$ | ||||
$10$ |
时间限制: \(2s\)
空间限制: \(512MB\)
来源
matthew99
题解
http://matthew99.blog.uoj.ac/blog/1771
下载
我的题解
orz 毛爷爷
这题很巧妙地利用了异或的自反性啊
毛爷爷的题解应该说得很清楚了
实际上就是
对于每次加入 \(S\) 点集的点对,把两个端点都异或上一个随机数
那么如果一条边 \((u,v)\) 被所有的点对经过
我们把 \(u\) 变成根,那就一定会有 \(v\) 所在的子树的异或和等于所有点对的异或和,因为每个点对一定会恰好有且仅有一个端点在 \(v\) 所在的子树内嘛
所以用LCT来维护子树信息,每次查询看两个异或和是否相等就可以了
这题目真的巧妙
(如果你用的是srand,然后被hack了,可以试试把你srand的数换成time(0))
#include<bits/stdc++.h>
#define ll long long
#define db double
#define ld long double
const int MAXN=100000+10,MAXM=300000+10;
int n,m,Sval,Sn;
struct edge{
int u,v,w;
};
edge S[MAXM];
#define lc(x) ch[(x)][0]
#define rc(x) ch[(x)][1]
struct LCT{
int ch[MAXN][2],fa[MAXN],rev[MAXN],val[MAXN],sum[MAXN],Isum[MAXN],stack[MAXN],cnt;
inline bool nroot(int x)
{
return lc(fa[x])==x||rc(fa[x])==x;
}
inline void reverse(int x)
{
std::swap(lc(x),rc(x));
rev[x]^=1;
}
inline void pushup(int x)
{
sum[x]=sum[lc(x)]^sum[rc(x)]^Isum[x]^val[x];
}
inline void pushdown(int x)
{
if(rev[x])
{
if(lc(x))reverse(lc(x));
if(rc(x))reverse(rc(x));
rev[x]=0;
}
}
inline void rotate(int x)
{
int f=fa[x],p=fa[f],c=(rc(f)==x);
if(nroot(f))ch[p][rc(p)==f]=x;
fa[ch[f][c]=ch[x][c^1]]=f;
fa[ch[x][c^1]=f]=x;
fa[x]=p;
pushup(f);
pushup(x);
}
inline void splay(int x)
{
cnt=0;
stack[++cnt]=x;
for(register int i=x;nroot(i);i=fa[i])stack[++cnt]=fa[i];
while(cnt)pushdown(stack[cnt--]);
for(register int y=fa[x];nroot(x);rotate(x),y=fa[x])
if(nroot(y))rotate((lc(y)==x)==(lc(fa[y])==y)?y:x);
pushup(x);
}
inline void access(int x)
{
for(register int y=0;x;x=fa[y=x])
{
splay(x);
Isum[x]^=sum[rc(x)];
rc(x)=y;
Isum[x]^=sum[rc(x)];
pushup(x);
}
}
inline void makeroot(int x)
{
access(x);splay(x);reverse(x);
}
inline void split(int x,int y)
{
makeroot(x);access(y);splay(y);
}
inline void link(int x,int y)
{
makeroot(x);access(y);splay(y);
fa[x]=y;
Isum[y]^=sum[x];
pushup(y);
}
inline void cut(int x,int y)
{
split(x,y);
fa[x]=lc(y)=0;
pushup(y);
}
};
LCT T;
#undef lc
#undef rc
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char c='\0')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(c!='\0')putchar(c);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
int main()
{
srand(time(0));
int id;
read(id);
read(n);read(m);
for(register int i=1;i<n;++i)
{
int u,v;
read(u);read(v);
T.link(u,v);
}
while(m--)
{
int opt;
read(opt);
if(opt==1)
{
int x,y,u,v;
read(x);read(y);read(u);read(v);
T.cut(x,y);T.link(u,v);
}
if(opt==2)
{
++Sn;
read(S[Sn].u);read(S[Sn].v);
S[Sn].w=rand();
Sval^=S[Sn].w;
T.access(S[Sn].u);T.splay(S[Sn].u);T.val[S[Sn].u]^=S[Sn].w;T.pushup(S[Sn].u);
T.access(S[Sn].v);T.splay(S[Sn].v);T.val[S[Sn].v]^=S[Sn].w;T.pushup(S[Sn].v);
}
if(opt==3)
{
int x;
read(x);
Sval^=S[x].w;
T.access(S[x].u);T.splay(S[x].u);T.val[S[x].u]^=S[x].w;T.pushup(S[x].u);
T.access(S[x].v);T.splay(S[x].v);T.val[S[x].v]^=S[x].w;T.pushup(S[x].v);
}
if(opt==4)
{
int x,y;
read(x);read(y);
T.makeroot(x);T.access(y);
if((T.Isum[y]^T.val[y])==Sval)puts("YES");
else puts("NO");
}
}
return 0;
}
【刷题】UOJ #207 共价大爷游长沙的更多相关文章
- UOJ #207. 共价大爷游长沙
#207. 共价大爷游长沙 链接:http://uoj.ac/problem/207 题意:给一棵树,要求支持加边.删边.询问一条边是否被所有路径覆盖.同时路径端点集合有加入与删除操作. 想法: 考虑 ...
- UOJ #207. 共价大爷游长沙 [lct 异或]
#207. 共价大爷游长沙 题意:一棵树,支持加边删边,加入点对,删除点对,询问所有点对是否经过一条边 一开始一直想在边权上做文章,或者从连通分量角度考虑,比较接近正解了,但是没想到给点对分配权值所以 ...
- UOJ #207. 共价大爷游长沙(LCT + 异或哈希)
题目 维护一颗动态树,并维护一个点对集合 \(S\) . 动态查询一条边,是否被集合中所有点对构成的路径包含. \(n \le 100000, m \le 300000\) 题解 orz 前辈 毛爷爷 ...
- [UOJ#207. 共价大爷游长沙]——LCT&随机化
题目大意: 传送门 给一颗动态树,给出一些路径并动态修改,每次询问一条边是否被所有路径覆盖. 题解: 先%一发myy. 开始感觉不是很可做的样子,发现子树信息无论维护什么都不太对…… 然后打开题目标签 ...
- 数据结构(动态树):UOJ 207 共价大爷游长沙
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABHwAAAJZCAIAAABUW7XHAAAgAElEQVR4nOy93cstx5Xm2f9TXh2EOe
- UOJ#207. 共价大爷游长沙 LCT
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ207.html 题解 第一次听说 LCT 还可以维护子树信息. 首先对于每一条路径 rand 一个值,分别 ...
- 【UOJ#207】共价大爷游长沙
题目链接 题目描述 火车司机出秦川,跳蚤国王下江南,共价大爷游长沙.每个周末,勤劳的共价大爷都会开车游历长沙市. 长沙市的交通线路可以抽象成为一个 \(n\) 个点 \(n−1\) 条边的无向图,点编 ...
- 【UOJ207】共价大爷游长沙(Link-Cut Tree,随机化)
[UOJ207]共价大爷游长沙(Link-Cut Tree,随机化) 题面 UOJ 题解 这题太神了 \(\%\%\%myy\) 看到动态的维护边很容易的想到了\(LCT\) 然后能否堵住一条路 我们 ...
- 「UOJ207」共价大爷游长沙
「UOJ207」共价大爷游长沙 解题思路 : 快速判断两个集合是否完全相等可以随机点权 \(\text{xor}\) 的思路可以用到这道题上面,给每一条路径随机一个点权,维护出经过每一条边的点权的 \ ...
随机推荐
- appium移动自动化测试---api键盘操作
模拟键盘输入也是非常重要的操作.这一小节来介绍那些关于键盘的操作. 1.sendKeys()方法 方法: sendKeys() 用法: driver.findElements(By.name(&quo ...
- Mysql试题集锦
1.一张表,里面有 ID 自增主键,当 insert 了 17 条记录之后,删除了第 15,16,17 条记录,再把 Mysql 重启,再 insert 一条记录,这条记录的 ID 是 18 还是 1 ...
- 【微服务架构】SpringCloud组件和概念介绍(一)
一:什么是微服务(Microservice) 微服务英文名称Microservice,Microservice架构模式就是将整个Web应用组织为一系列小的Web服务.这些小的Web服务可以独立地编译及 ...
- 解决java读取大文件内存溢出问题
1. 传统方式:在内存中读取文件内容 读取文件行的标准方式是在内存中读取,Guava 和Apache Commons IO都提供了如下所示快速读取文件行的方法: Files.readLines(new ...
- 路由器终端常用linux命令汇总(持续更新)
ls:显示文件名与相关属性 ls -al;ls -l;ls -a 第一列: d:表示目录,dir. -:表示文件. l:表示链接文件,linkfile. 接下来的字符三个为一组,且均为rwx这3个字母 ...
- node jade模板数据库操作
/* Navicat MySQL Data Transfer Source Server : localhost Source Server Version : 50519 Sourc ...
- 跨域Ajax -- jsonp和cors
跨域Ajax - jsonp - cors 参考博客: http://www.cnblogs.com/wupeiqi/articles/5703697.html http://www.cnblogs. ...
- fetch上传文件
通过简单的配置,实现form表单文件上传 var formData = new FormData(); var fileField = document.querySelector("inp ...
- java.util.ConcurrentModificationException: null
是因为在map.foreach中又put新的值了 在map.foreach中可能是不可以增删改
- Week4-作业1:阅读与博客
第四章.两人合作 1.原文: 在变量面前加上有意义的前缀,程序员就能一眼看出变量的类型及相应的语义.这就是“匈牙利命名法”的用处.还有一些地方不适合用“匈牙利命名法”,比如,在一些强类型的语言(如C# ...