初始的时候有一个只有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并查集的更多相关文章

  1. Gym 100814C Connecting Graph 并查集+LCA

    Description standard input/output Statements Alex is known to be very clever, but Walter does not be ...

  2. Codeforces Gym 100231B Intervals 线段树+二分+贪心

    Intervals 题目连接: http://codeforces.com/gym/100231/attachments Description 给你n个区间,告诉你每个区间内都有ci个数 然后你需要 ...

  3. codeforces 701E E. Connecting Universities(树的重心)

    题目链接: E. Connecting Universities time limit per test 3 seconds memory limit per test 256 megabytes i ...

  4. Codeforces Gym 101194G Pandaria (2016 ACM-ICPC EC-Final G题, 并查集 + 线段树合并)

    题目链接  2016 ACM-ICPC EC-Final Problem G 题意  给定一个无向图.每个点有一种颜色. 现在给定$q$个询问,每次询问$x$和$w$,求所有能通过边权值不超过$w$的 ...

  5. 2018.08.30 NOIP模拟 graph(dfs序/树剖+线段树)

    [描述] 给你一个图,一共有 N 个点,2*N-2 条有向边. 边目录按两部分给出 1. 开始的 n-1 条边描述了一颗以 1 号点为根的生成树,即每个点都可以由 1 号点 到达. 2. 接下来的 N ...

  6. 【BZOJ3999】【TJOI2015】旅游 树剖

    题目大意 给你一棵树,有\(n\)个点.有\(q\)个操作,每次要你从\(x\)到\(y\)的路径上选两个点,使得距离\(x\)比较远的点的点权\(-\)距离\(x\)比较近的点的点权最大,然后把这条 ...

  7. SPOJ375Query on a tree I(树剖+线段树)(询问边)

    ιYou are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...

  8. codeforces gym 100553I

    codeforces gym 100553I solution 令a[i]表示位置i的船的编号 研究可以发现,应是从中间开始,往两边跳.... 于是就是一个点往两边的最长下降子序列之和减一 魔改树状数 ...

  9. 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 ...

随机推荐

  1. 浏览器端-W3School-HTML:HTML DOM Script 对象

    ylbtech-浏览器端-W3School-HTML:HTML DOM Script 对象 1.返回顶部 1. HTML DOM Script 对象 Script 对象 Script 对象表示 HTM ...

  2. Go语言基本类型

    1.Go语言fmt包详解 fmt.Println() ###常用打印 fmt.Print() fmt.Printf() ###格式化 fmt.Sprintf() ###字符串拼接 a)普通占位符 占位 ...

  3. Jmeter(六)事务

    事务是性能测试之必不可少的关注点, Jmeter默认把每一个请求都统计成了一个事务, 但有时候我们根据业务需求, 会把多个操作统计成一个事务, Jmeter当然也考虑到了这个需求, 因此我们可以通过逻 ...

  4. sublime3配置php开发环境

    Sublime3 3143 1.用包管理器安装SublimeLinter ctrl+shift+p Package Control: install package SublimeLinter 注意: ...

  5. python pytorch numpy DNN 线性回归模型

    1.直接奉献代码,后期有入门更新,之前一直在学的是TensorFlow, import torch from torch.autograd import Variable import torch.n ...

  6. 【图像处理】【计算机视觉】findContours的使用

    原文地址:findContours函数参数说明及相关函数作者:鸳都学童 findContours函数,这个函数的原型为: void findContours(InputOutputArray imag ...

  7. 注解@Slf4j的作用

    lombok.extern.slf4j 代码: @Slf4j public class LogExample { } 产生以下代码: public class LogExample { private ...

  8. 访问DataGridView的Rows报了OutOfIndexRangeException错误

    DataGridView绑定了一个List<Entity>实体集合,在遍历DataGridView的每一行DataBoundItem时候,如果符合某个条件的话,则移除List<Ent ...

  9. linux whoami 显示当前用户的用户名

    [root@MongoDB ~]# whoami root

  10. BadUsb简单用法示例

    所需硬件  badusb 自行淘宝  驱动程序会自动安装,若未自动安装自行百度 所需工具  arduino-1.5.5-r2用于编辑代码并上传至badusb   badusb连接至电脑   打开ard ...