题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5458

给你n个点,m条边,q个操作,操作1是删边,操作2是问u到v之间的割边有多少条。

这题要倒着做才容易,倒着加边。

因为这题最后保证所有的点一定连通,所以可以构建一棵树,树链剖分一下。要是u到v之间只有一条边,那便是一条割边。而加边的话,就是将u到v之间的边权都+1,边权等于1的话是桥,大于1的话就不是了。所以我们初始化树的时候,可以将边权初始化为1,加边操作将边权赋值为0。求u到v的割边个数的话,就是求u到v的和。

中间存边我用multiset( map 超时),然后用并查集判断是不是一棵完整的树从而看情况加边。

 //#pragma comment(linker, "/STACK:102400000, 102400000")
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>
using namespace std;
typedef long long LL;
typedef pair <int, int> P;
const int N = 1e5 + ;
struct Edge {
int next, to;
}edge[N << ];
multiset <P> myset; //存 构建的树的边
int head[N], tot;
int pre[N], son[N], dep[N], size[N], cnt; //son:重儿子
int top[N], id[N];
int uu[N], vv[N], c[N]; //q个操作c uu vv
int x[N], y[N]; //开始输入的m条边x y
int ans[N]; //答案
int par[N]; //并查集 void init(int n) {
for(int i = ; i <= n; ++i) {
par[i] = i;
head[i] = -;
}
tot = cnt = ;
myset.clear();
} inline void add(int u, int v) {
edge[tot].next = head[u];
edge[tot].to = v;
head[u] = tot++;
} inline int search(int n) {
if(n == par[n])
return n;
return par[n] = search(par[n]);
} void dfs1(int u, int p, int d) {
dep[u] = d, size[u] = , son[u] = u, pre[u] = p;
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to;
if(v == p)
continue;
dfs1(v, u, d + );
if(size[v] >= size[son[u]])
son[u] = v;
size[u] += size[v];
}
} void dfs2(int u, int p, int t) {
top[u] = t, id[u] = ++cnt;
if(son[u] != u)
dfs2(son[u], u, t);
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to;
if(v == p || v == son[u])
continue;
dfs2(v, u, v);
}
} struct SegTree {
int l, r, val, lazy, mid;
}T[N << ]; void build(int p, int l, int r) {
T[p].mid = (l + r) >> ;
T[p].l = l, T[p].r = r, T[p].lazy = ;
if(l == r) {
T[p].val = ;
return ;
}
build(p << , l, T[p].mid);
build((p << )|, T[p].mid + , r);
T[p].val = T[p << ].val + T[(p << )|].val;
} inline void pushdown(int p) {
int ls = p << , rs = (p << )|;
T[ls].lazy = T[rs].lazy = T[ls].val = T[rs].val = ;
T[p].lazy = ;
} void update(int p, int l, int r) {
if(T[p].val == )
return ;
if(T[p].l == l && T[p].r == r) {
T[p].lazy = T[p].val = ;
return ;
}
if(!T[p].lazy) {
pushdown(p);
}
if(r <= T[p].mid) {
update(p << , l, r);
}
else if(l > T[p].mid) {
update((p << )|, l, r);
}
else {
update(p << , l, T[p].mid);
update((p << )|, T[p].mid + , r);
}
T[p].val = T[p << ].val + T[(p << )|].val;
} int query(int p, int l, int r) {
if(T[p].val == )
return ;
if(T[p].l == l && T[p].r == r) {
return T[p].val;
}
if(!T[p].lazy) {
pushdown(p);
}
if(r <= T[p].mid) {
return query(p << , l , r);
}
else if(l > T[p].mid) {
return query((p << )| , l , r);
}
else {
return query(p << , l , T[p].mid) + query((p << )| , T[p].mid + , r);
}
} void change(int u, int v) {
int fu = top[u], fv = top[v];
while(fu != fv) {
if(dep[fu] >= dep[fv]) {
update(, id[fu], id[u]);
u = pre[fu];
fu = top[u];
}
else {
update(, id[fv], id[v]);
v = pre[fv];
fv = top[v];
}
}
if(u == v)
return ;
else if(dep[u] >= dep[v])
update(, id[son[v]], id[u]);
else
update(, id[son[u]], id[v]);
} int find(int u, int v) {
int fu = top[u], fv = top[v], res = ;
while(fu != fv) {
if(dep[fu] >= dep[fv]) {
res += query(, id[fu], id[u]);
u = pre[fu];
fu = top[u];
}
else {
res += query(, id[fv], id[v]);
v = pre[fv];
fv = top[v];
}
}
if(u == v)
return res;
else if(dep[u] >= dep[v])
return res + query(, id[son[v]], id[u]);
else
return res + query(, id[son[u]], id[v]);
} int main()
{
int t, n, m, q, u, v;
scanf("%d", &t);
for(int ca = ; ca <= t; ++ca) {
scanf("%d %d %d", &n, &m, &q);
init(n);
for(int i = ; i <= m; ++i) {
scanf("%d %d", x + i, y + i);
if(x[i] > y[i])
swap(x[i], y[i]);
myset.insert(make_pair(x[i], y[i])); //先存边
}
for(int i = ; i <= q; ++i) {
scanf("%d %d %d", c + i, uu + i, vv + i);
if(uu[i] > vv[i])
swap(uu[i], vv[i]);
if(c[i] == ) {
auto pos = myset.find(make_pair(uu[i], vv[i])); //去除要删的边
myset.erase(pos);
}
}
int f = ;
for(auto i = myset.begin(); i != myset.end(); ++i) {
u = search(i->first), v = search(i->second);
if(u == v) { //不成环
++f;
x[f] = i->first, y[f] = i->second; //此时的x y存的是非树也非删的边
continue;
}
par[u] = v;
add(i->first, i->second);
add(i->second, i->first);
}
dfs1(, -, );
dfs2(, -, );
printf("Case #%d:\n", ca);
build(, , n);
for(int i = ; i <= f; ++i) {
change(x[i], y[i]);
}
f = ;
for(int i = q; i >= ; --i) {
if(c[i] == ) {
change(uu[i], vv[i]);
}
else {
ans[++f] = find(uu[i], vv[i]);
}
}
for(int i = f; i >= ; --i) {
printf("%d\n", ans[i]);
}
}
return ;
}

写的我比较头痛,调试了比较久...

HDU 5458 Stability (树链剖分+并查集+set)的更多相关文章

  1. hdu 5458 Stability(树链剖分+并查集)

    Stability Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)Total ...

  2. bzoj3694: 最短路(树链剖分/并查集)

    bzoj1576的帮我们跑好最短路版本23333(双倍经验!嘿嘿嘿 这题可以用树链剖分或并查集写.树链剖分非常显然,并查集的写法比较妙,涨了个姿势,原来并查集的路径压缩还能这么用... 首先对于不在最 ...

  3. [BZOJ2238]Mst 最小生成树+树链剖分/并查集

    链接 题解 先构建出最小生成树,如果删的是非树边,直接输出答案 否则问题转化为,把该边删掉后剩下两个联通块,两个端点分别在两个块内的最小边权,LCT可以维护 不妨换一种思考方向:考虑一条非树边可以代替 ...

  4. HDU 5044 (树链剖分+树状数组+点/边改查)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5044 题目大意:修改链上点,修改链上的边.查询所有点,查询所有边. 解题思路: 2014上海网赛的变 ...

  5. HDU 3966(树链剖分+点修改+点查询)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 题目大意:营地的分布成树型.每个营地都有一些人,每次修改修改一条链上的所有营地的人数,每次查询单 ...

  6. HDU 5044 Tree --树链剖分

    题意:给一棵树,两种操作: ADD1: 给u-v路径上所有点加上值k, ADD2:给u-v路径上所有边加上k,初始值都为0,问最后每个点和每条边的值,输出. 解法:树链剖分可做,剖出来如果直接用线段树 ...

  7. HDU - 3966-Aragorn' Story(树链剖分+线段树)

    链接:https://vjudge.net/problem/HDU-3966 题意: Our protagonist is the handsome human prince Aragorn come ...

  8. HDU 3966 RE 树链剖分 线段树 Aragorn's Story

    题意: 给出一棵树,每个顶点上有一个权值. 操作:选择一条路径,并将路径上所有的点的权值同时加或减某个数. 查询:某个点的当前权值 分析: 树链剖分完毕后,就是简单的线段树区间更新. 提交的时候注意要 ...

  9. HDU 5242 利用树链剖分思想进行贪心

    题目大意: 在给定带权值节点的树上从1开始不回头走到某个底端点后得到所有经过的点的权值后,这些点权值修改为0,到达底部后重新回到1,继续走,问走k次,最多能得到多少权值之和 这其实就是相当于每一次都走 ...

随机推荐

  1. 4630 no pain no game 树状数组

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4630 题意:给你N个数,然后给你M个询问,每个询问包含一个l 一个r,问你lr 这个区间中任意两个数最 ...

  2. UIDevice通知

    UIDevice通知 UIDevice类提供了一个单例对象,它代表着设备,通过它可以获得一些设备相关的信息,比如电池电量值(batteryLevel).电池状态(batteryState).设备的类型 ...

  3. UISlide

    UISlide属性   1.   minimumValue  : 当值可以改变时,滑块可以滑动到最小位置的值,默认为0.0 _slider.minimumValue = 10.0; 2.   maxi ...

  4. 用canvas实现图片滤镜效果详解之视频效果

    这是一个很有意思的特效,模拟摄像机拍摄电视屏幕画面时出现点状颗粒的效果.颗粒的大小通过变换矩阵实现,可以任意调节,有兴趣研究的朋友可以尝试更多的效果,代码没有经过优化,只是一个粗糙的Demo,大家可以 ...

  5. 剑指offer-第二章算法之斐波拉契数列(青蛙跳台阶)

    递归与循环 递归:在一个函数的内部调用这个函数. 本质:把一个问题分解为两个,或者多个小问题(多个小问题相互重叠的部分,会存在重复的计算) 优点:简洁,易于实现. 缺点:时间和空间消耗严重,如果递归调 ...

  6. MySQL与Oracle 差异比较之三函数

    函数 编号 类别 ORACLE MYSQL 注释 1 数字函数 round(1.23456,4) round(1.23456,4) 一样:ORACLE:select round(1.23456,4) ...

  7. linearlayout 水平垂直居中

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&q ...

  8. Linux makefile教程之隐含规则九[转]

    隐含规则 ———— 在 我们使用Makefile时,有一些我们会经常使用,而且使用频率非常高的东西,比如,我们编译C/C++的源程序为中间目标文件(Unix下是[.o] 文件,Windows下是[.o ...

  9. delphi 注册表操作(读取、添加、删除、修改)完全手册

    DELPHI VS PASCAL(87)  32位Delphi程序中可利用TRegistry对象来存取注册表文件中的信息. 一.创建和释放TRegistry对象 1.创建TRegistry对象.为了操 ...

  10. 【剑指offer 面试题34】丑数

    只包含因子2.3.5的数称作丑数. #include <iostream> #include <vector> using namespace std; int GetUgly ...