Codeforces Gym 100814C Connecting Graph 树剖并查集/LCA并查集
初始的时候有一个只有n个点的图(n <= 1e5), 现在进行m( m <= 1e5 )次操作
每次操作要么添加一条无向边, 要么询问之前结点u和v最早在哪一次操作的时候连通了
/*
* Author: Gatevin
* Created Time: 2015/11/21 14:02:38
* File Name: Sakura_Chiyo.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-);
typedef long long lint; #define maxn 100010 int top[maxn];
int grandson[maxn];
int dep[maxn];
int siz[maxn];
int belong[maxn];
int father[maxn];
int Q[maxn];
int cnt;
int hson[maxn]; int q, s;
bool vis[maxn];
int T, n, m;
int id[maxn];
int antiID[maxn]; struct Edge
{
int u, v, w, nex;
Edge(int _u, int _v, int _w, int _nex)
{
u = _u, v = _v, w = _w, nex = _nex;
}
Edge(){}
}; int head[maxn];
int tot;
Edge edge[maxn << ];
int w[maxn];
int idx; void add_Edge(int x, int y, int w)
{
edge[++tot] = Edge(x, y, w, head[x]);
head[x] = tot;
} void split(int root)
{
int l = , r = ;
dep[Q[r] = root] = ;
father[root] = -;
w[root] = ;
while(l < r)
{
int x = Q[++l];
if(head[x] == -) continue;
for(int j = head[x]; j + ; j = edge[j].nex)
{
int y = edge[j].v;
if(y == father[x]) continue;
w[y] = edge[j].w;
dep[Q[++r] = y] = dep[x] + ;
father[y] = x;
}
}
for(int i = r ; i ; i--)
{
int x = Q[i], p = -;
siz[x] = ;
if(head[x] == -) continue;
for(int j = head[x]; j + ; j = edge[j].nex)
{
int y = edge[j].v;
if(y == father[x]) continue;
siz[x] += siz[y];
if(p == - || (p > && siz[y] > siz[p]))
p = y;
}
if(p == -)
{
hson[x] = -;
grandson[++cnt] = x;
belong[top[cnt] = x] = cnt;
}
else
{
hson[x] = p;
belong[x] = belong[p];
top[belong[x]] = x;
}
}
//int idx = 0;
//memset(vis, 0, sizeof(vis));
for(int i = r; i; i--)
{
int x = Q[i];
if(vis[x]) continue;
vis[x] = ;
id[x] = ++idx;
antiID[idx] = x;
while(father[x] != - && belong[father[x]] == belong[x] && !vis[father[x]])
{
x = father[x];
id[x] = ++idx;
antiID[idx] = x;
vis[x] = ;
}
}
return;
} #define lson l, mid, rt << 1
#define rson mid + 1, r , rt << 1 | 1
int val[maxn << ]; void pushUp(int rt)
{
val[rt] = max(val[rt << ], val[rt << | ]);
return;
} void build(int l, int r, int rt)
{
if(l == r)
{
val[rt] = w[antiID[l]];
return;
}
int mid = (l + r) >> ;
build(lson);
build(rson);
pushUp(rt);
} void update(int l, int r, int rt, int pos, int value)
{
if(l == r)
{
val[rt] = value;
return;
}
int mid = (l + r) >> ;
if(pos <= mid) update(lson, pos, value);
else update(rson, pos, value);
pushUp(rt);
return;
} int query(int l, int r, int rt, int L, int R)
{
if(l >= L && r <= R)
return val[rt];
int mid = (l + r) >> ;
int ret = ;
if(mid >= L) ret = max(ret, query(lson, L, R));
if(mid + <= R) ret = max(ret, query(rson, L, R));
return ret;
} int answer(int x, int y)
{
int ans= ;
while(top[belong[x]] != top[belong[y]])
{
if(dep[top[belong[x]]] < dep[top[belong[y]]])
swap(x, y);
ans = max(ans, query(, n, , id[x], id[top[belong[x]]]));
x = father[top[belong[x]]];
}
if(x == y) return ans;
if(dep[x] < dep[y]) swap(x, y);
ans = max(ans, query(, n, , id[x], id[hson[y]]));
return ans;
} void change(int x, int w)
{
x <<= ;
int u = edge[x].u, v = edge[x].v;
if(father[u] == v)
update(, n, , id[u], w);
else update(, n, , id[v], w);
return;
} struct Op
{
int type, u, v, fu, fv, edge;
bool add;
Op(int _t, int _u, int _v)
{
type = _t, u = _u, v = _v;
add = false;
}
Op(){}
}; Op op[maxn]; int fa[maxn];
int find(int x)
{
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
int E;//添加的边的次数
void Union(int x, int y, int opid)
{
int fx = find(x);
int fy = find(y);
op[opid].fu = fx, op[opid].fv = fy;
op[opid].add = false;
if(fx != fy)
{
fa[fx] = fy;
op[opid].add = true;
op[opid].edge = ++E;
add_Edge(fx, fy, opid);
add_Edge(fy, fx, opid);
}
} int ans[maxn]; int read()
{
int x = ;
char c;
while(!isdigit(c = getchar())) continue;
x = (x << ) + (x << ) + c - '';
while(isdigit(c = getchar())) x = (x << ) + (x << ) + c - '';
return x;
} int sis[maxn]; int main()
{
//scanf("%d", &T);
T = read();
int cas = ;
while(T--)
{
cas++;
//scanf("%d %d", &n, &m);
n = read(), m = read();
memset(head, -, sizeof(head));
tot = ; E = ;
for(int i = ; i <= n; i++) fa[i] = i;
for(int i = ; i <= m; i++)
{
//scanf("%d %d %d", &op[i].type, &op[i].u, &op[i].v);
op[i].type = read(), op[i].u = read(), op[i].v = read();
if(op[i].type == ) Union(op[i].u, op[i].v, i);
}
idx = ;
memset(vis, , sizeof(vis));
cnt = ;
for(int i = ; i <= n; i++)
{
int fi = find(i);
if(sis[fi] != cas)
{
split(fi);
sis[fi] = cas;
}
}
build(, n, );
for(int i = m; i > ; i--)
{
if(op[i].type == )//query
{
int u = op[i].u, v = op[i].v;
if(find(u) != find(v))//一直就是不连通的
{
ans[i] = -;
continue;
}
ans[i] = answer(op[i].u, op[i].v);
}
else
{
if(op[i].add == false) continue;//这个操作没有造成过添加边的影响
change(op[i].edge, 1e9);
}
}
for(int i = ; i <= m; i++)
if(op[i].type == )
printf("%d\n", ans[i] == 1e9 ? - : ans[i]);
}
return ;
}
Codeforces Gym 100814C Connecting Graph 树剖并查集/LCA并查集的更多相关文章
- Gym 100814C Connecting Graph 并查集+LCA
Description standard input/output Statements Alex is known to be very clever, but Walter does not be ...
- Codeforces Gym 100231B Intervals 线段树+二分+贪心
Intervals 题目连接: http://codeforces.com/gym/100231/attachments Description 给你n个区间,告诉你每个区间内都有ci个数 然后你需要 ...
- codeforces 701E E. Connecting Universities(树的重心)
题目链接: E. Connecting Universities time limit per test 3 seconds memory limit per test 256 megabytes i ...
- Codeforces Gym 101194G Pandaria (2016 ACM-ICPC EC-Final G题, 并查集 + 线段树合并)
题目链接 2016 ACM-ICPC EC-Final Problem G 题意 给定一个无向图.每个点有一种颜色. 现在给定$q$个询问,每次询问$x$和$w$,求所有能通过边权值不超过$w$的 ...
- 2018.08.30 NOIP模拟 graph(dfs序/树剖+线段树)
[描述] 给你一个图,一共有 N 个点,2*N-2 条有向边. 边目录按两部分给出 1. 开始的 n-1 条边描述了一颗以 1 号点为根的生成树,即每个点都可以由 1 号点 到达. 2. 接下来的 N ...
- 【BZOJ3999】【TJOI2015】旅游 树剖
题目大意 给你一棵树,有\(n\)个点.有\(q\)个操作,每次要你从\(x\)到\(y\)的路径上选两个点,使得距离\(x\)比较远的点的点权\(-\)距离\(x\)比较近的点的点权最大,然后把这条 ...
- SPOJ375Query on a tree I(树剖+线段树)(询问边)
ιYou are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...
- codeforces gym 100553I
codeforces gym 100553I solution 令a[i]表示位置i的船的编号 研究可以发现,应是从中间开始,往两边跳.... 于是就是一个点往两边的最长下降子序列之和减一 魔改树状数 ...
- POJ3237 Tree(树剖+线段树+lazy标记)
You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbe ...
随机推荐
- bat脚本延时启动exe和bat文件
@echo off ping >nul start D:\exe\a.exe start "C:\Program Files\维护工具\卸载清除一键清理系统垃圾文件.bat" ...
- Day06:方法 / 猜字母游戏
JAVA方法 方法就是处理一个业务所需要编写的代码的代码段 方法特性 一个方法处理一个业务 方法代码编写,不和其他方法冲突 方法定义后可以随意调用 将main方法中的所有代码分散到各个普通方法中 减少 ...
- HCL试验3
PC端配置:配置ip地址 配置网关 交换机(左)配置:①创建VLAN system-view vlan 10 vlan 20 ②配置PC端接口 interface gi 1/0/1 port link ...
- A1139-引爆炸弹 计蒜客 bfs剪枝
题目链接 https://nanti.jisuanke.com/t/A1139 在一个 n \times mn×m 的方格地图上,某些方格上放置着炸弹.手动引爆一个炸弹以后,炸弹会把炸弹所在的行和列上 ...
- Ubuntu环境配置机器安装驱动
ubuntu_environment_config.md thead > tr > th { text-align: left; border-bottom: 1px solid; } t ...
- Linux执行命令./command与直接输入命令的区别
我们知道查看文件属性的命令ls的完整文件路径为:/bin/ls(这是绝对路径,)问什么我可以在任何地方执行,任何目录下输入ls就一定可以显示出一些信息而不会说找不到该/bin/ls命令,这是因为不同的 ...
- vue--生命周期演示
vue实例的生命周期:https://cn.vuejs.org/v2/guide/instance.html#%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA-Vue-%E5% ...
- 2019JAVA第四次实验报告
JAVA实验报告 班级 计科二班 学号 20188442 姓名 吴怡君 完成时间 2019/9/29 评分等级 实验四 类的继承 1.实验目的 掌握类的继承方法: 变量的继承和覆盖,方法的继承.重载和 ...
- Neo4j下载与使用
Neo4j 官网 : https://neo4j.com/ Neo4j 国内: http://neo4j.com.cn/topic/5b003eae9662eee704f31cee http://we ...
- python之入门
第一章 入门 1.1 变量-输出 a = 1 # 声明变量 a # 变量的名字 = # 赋值 1 # 值 变量定义的规则: 1.变量由数字,字母,下划线组成 2.不能以数字开头 3.不能使用pytho ...