Stability

Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)
Total Submission(s): 1347    Accepted Submission(s): 319

Problem Description
Given an undirected connected graph G with n nodes and m edges, with possibly repeated edges and/or loops. The stability of connectedness between node u and node v is defined by the number of edges in this graph which determines the connectedness between them (once we delete this edge, node u and v would be disconnected).

You need to maintain the graph G, support the deletions of edges (though we guarantee the graph would always be connected), and answer the query of stability for two given nodes.

 
Input
There are multiple test cases(no more than 3 cases), and the first line contains an integer t, meaning the totally number of test cases.

For each test case, the first line contains three integers n, m and q, where 1≤n≤3×104,1≤m≤105 and 1≤q≤105. The nodes in graph G are labelled from 1to n.

Each of the following m lines contains two integers u and v describing an undirected edge between node u and node v.

Following q lines - each line describes an operation or a query in the formats:
⋅ 1 a b: delete one edge between a and b. We guarantee the existence of such edge.
⋅ 2 a b: query the stability between a and b.

 
Output
For each test case, you should print first the identifier of the test case.

Then for each query, print one line containing the stability between corresponding pair of nodes.

 
Sample Input
1
10 12 14
1 2
1 3
2 4
2 5
3 6
4 7
4 8
5 8
6 10
7 9
8 9
8 10
2 7 9
2 7 10
2 10 6
2 10 5
1 10 6
2 10 1
2 10 6
2 3 10
1 8 5
2 5 10
2 4 5
1 7 9
2 7 9
2 10 5
 
Sample Output
Case #1:
0
0
0
0
2
4
3
3
2
3
4
/*
hdu 5458 Stability(树链剖分+并查集) problem:
给你一个无向图(可能有重边or环). 1.删除a,b之间的边 2.查询a,b的必要边(即删除后a b无法连通) solve:
最开始想的是建图的时候一直维持一棵树. 如果u,v上面出现环,那么u->v整个链上都可以置为0.因为它们任意两点之间都不可能有必要边
但是后面操作中会删除边,所以不知道树的形状,会导致后面的查询出现问题. 后来考虑倒着操作,先弄出最后操作完的图.本来还担心最后会被切成多个不相连图, 但是
题目:we guarantee the graph would always be connected 保证了操作完后必然是 树或者有环图.
如果是有环图的话可以用过上面的思路转换成树的,最后就成了树链上的操作,所以树链剖分就能做 将所有边记录下来,然后将1操作删除的边除去. 如果最后是有环图(并查集判断)的话,将重复的边记录下,然后建树.
而重复的边会导致 u->v链上面两两没有必要边,于是将置为0. 得出了最后这个树,接着就是倒着操作了
1操作:在u->v上加边 ----> 将u->v整个链上都可以置为0
2操作:查询u->v上的必要边 hhh-2016-08-26 11:06:45
*/
#pragma comment(linker,"/STACK:124000000,124000000")
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <math.h>
#include <queue>
#include <map>
#include <set>
#define lson i<<1
#define rson i<<1|1
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define scanfi(a) scanf("%d",&a)
#define scanfl(a) scanf("%I64d",&a)
#define key_val ch[ch[root][1]][0]
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 40010;
const int maxm = 2e5 + 1000;
int head[maxn],tot,pos,son[maxn];
int top[maxn],fp[maxn],fa[maxn],dep[maxn],num[maxn],p[maxn];
int par[maxn];
int n,m,q;
struct Edge
{
int to,next;
} edge[maxm << 1];
int fin_par(int x)
{
if(par[x] == -1) return x;
return par[x] = fin_par(par[x]);
}
void ini()
{
clr(par,-1);
tot = 0,pos = 1;
clr(head,-1),clr(son,-1);
} void add_edge(int u,int v)
{
edge[tot].to = v,edge[tot].next = head[u],head[u] = tot++;
} void dfs1(int u,int pre,int d)
{
// cout << u << " " <<pre <<" " <<d <<endl;
dep[u] = d;
fa[u] = pre,num[u] = 1;
for(int i = head[u]; ~i; i = edge[i].next)
{
int v = edge[i].to;
if(v != pre)
{
dfs1(v,u,d+1);
num[u] += num[v];
if(son[u] == -1 || num[v] > num[son[u]])
son[u] = v;
}
}
} void getpos(int u,int sp)
{
top[u] = sp;
p[u] = pos++;
fp[p[u]] = u;
if(son[u] == -1)return ;
getpos(son[u],sp);
for(int i = head[u]; ~i ; i = edge[i].next)
{
int v = edge[i].to;
if(v != son[u] && v != fa[u])
getpos(v,v);
}
} struct node
{
int same;
int val;
int l,r,mid;
} tree[maxn << 2]; void push_up(int i)
{
tree[i].val = tree[lson].val + tree[rson].val;
} void build(int i,int l,int r)
{
tree[i].same = -1;
tree[i].l = l,tree[i].r = r;
tree[i].mid=(l+r) >>1; if(l == r)
{
if(fp[l] == 1)
tree[i].val = 0;
else
tree[i].val = 1;
// cout << fp[l]<<":" << tree[i].val <<endl;
return;
}
build(lson,l,tree[i].mid);
build(rson,tree[i].mid+1,r);
push_up(i);
} void push_down(int i)
{
if(tree[i].same != -1)
{
tree[lson].same = tree[i].same;
tree[rson].same = tree[i].same;
tree[lson].val = tree[rson].val = 0;
tree[i].same = -1;
}
} void update_area(int i,int l,int r)
{
if(tree[i].l >= l && tree[i].r <= r)
{
tree[i].val= 0;
tree[i].same= 0;
return ;
}
push_down(i);
if(l <= tree[i].mid)
update_area(lson,l,r);
if(r > tree[i].mid)
update_area(rson,l,r);
push_up(i);
return ;
} int query(int i,int l,int r)
{
if(tree[i].l >= l && tree[i].r <= r)
return tree[i].val;
int tcnt = 0;
push_down(i);
if(l <= tree[i].mid)
tcnt += query(lson,l,r);
if(r > tree[i].mid)
tcnt += query(rson,l,r);
push_up(i);
return tcnt;
} void make_update(int u,int v)
{
int f1 = top[u],f2 = top[v];
while(f1 != f2)
{
if(dep[f1] < dep[f2])swap(f1,f2),swap(u,v);
update_area(1,p[f1],p[u]);
u = fa[f1] , f1 =top[u];
}
if(u == v)
return ;
if(dep[u] > dep[v]) swap(u,v);
update_area(1,p[son[u]],p[v]);
} int make_query(int u,int v)
{
int ans = 0;
int f1= top[u],f2 = top[v];
while(f1 != f2)
{
if(dep[f1] < dep[f2])
{
swap(f1,f2),swap(u,v);
}
ans += query(1,p[f1],p[u]);
// cout << p[f1] <<" " <<p[u] <<" "<<ans << endl;
u = fa[f1] , f1 = top[u];
}
if(u == v)
return ans;
if(dep[u] > dep[v]) swap(u,v);
ans += query(1,p[son[u]],p[v]);
// cout << p[u]+1 <<" " <<p[v] <<" "<<ans << endl;
return ans ;
} int l[maxm],r[maxm],op[maxm];
int ans[maxm];
struct Point
{
int l,r;
Point() {}
Point(int x,int y):l(x),r(y) {}
bool operator <(const Point &a)const
{
if(l != a.l)
return l < a.l;
else
return r < a.r;
}
};
multiset<Point> vec;
multiset<Point> another;
multiset<Point>::iterator it;
int main()
{
// freopen("in.txt","r",stdin);
int T,u,v,cas = 1;
scanfi(T);
while(T--)
{
ini();
vec.clear(),another.clear();
scanfi(n),scanfi(m),scanfi(q);
for(int i = 1; i <= m; i++)
{
scanfi(u),scanfi(v);
if(u > v) swap(u,v);
vec.insert(Point(u,v));
}
for(int i = 1; i <= q; i++)
{
scanf("%d%d%d",&op[i],&l[i],&r[i]);
if(op[i] == 1)
{
if(l[i] > r[i]) swap(l[i],r[i]);
vec.erase(vec.lower_bound(Point(l[i],r[i])));
}
}
// cout << vec.size() <<endl;
for( it = vec.begin(); it != vec.end(); it++)
{
Point t = *it;
u = t.l,v = t.r;
int tu = fin_par(u),tv = fin_par(v);
// cout << u <<" " << v << " " << tu << " " <<tv <<endl;
if(tu == tv)
{
another.insert(Point(u,v));
continue;
}
par[tu] = tv;
add_edge(u,v);
add_edge(v,u);
}
// cout << another.size() <<endl;
dfs1(1,0,0);
getpos(1,1);
build(1,1,pos-1);
printf("Case #%d:\n",cas++);
for( it = another.begin(); it != another.end(); it++)
{
Point t = *it;
u = t.l,v = t.r;
make_update(u,v);
}
int ob = 0;
for(int i = q; i > 0; i--)
{
u = l[i],v = r[i];
// cout << op[i]<<" "<< u << " " << v <<endl; if(op[i] == 2)
{
ans[ob++] = make_query(u,v);
}
else
{
make_update(u,v);
}
}
for(int i = ob-1;i >=0;i--)
{
printf("%d\n",ans[i]);
}
}
return 0;
}

  

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

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

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5458 给你n个点,m条边,q个操作,操作1是删边,操作2是问u到v之间的割边有多少条. 这题要倒着做才 ...

  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. C实现单链表

    typedef int DataType; typedef struct ListNode { DataType data; struct ListNode* next; }ListNode; //初 ...

  2. Struts2之Struts2的标签库

    前言: Struts2提供了大量的标签 ,用来帮助开发表现层页面,这些表现一方面解决了美观性的需求,因为它们具有html标签一样的外观,另一方面它们解决了功能性的需求, 因为它们具有jsp脚本一样的逻 ...

  3. nyoj 对决吃桃

    时间限制:3000 ms  |  内存限制:65535 KB 难度:0   描述 有一堆桃子不知数目,猴子第一天吃掉一半,又多吃了一个,第二天照此方法,吃掉剩下桃子的一半又多一个,天天如此,到第m天早 ...

  4. 第二章 初识JSP

    第二章   初识JSP 一.JSP简述 1.是JSP JSP是指在HTML中嵌入Java脚本语言.全称(Java Server Pages) 当用户通过浏览器访问Web应用时,使用JSP容器对请求的J ...

  5. WPF 自定义RadioButton样式

    一.RadioButton基本样式 RadioButton基本样式包含两种状态,这里也是使用两张图片来代替两种状态,当然你也可以通过IconFont或Path来替换这两种状态. 效果如下: 样式代码如 ...

  6. 记一次将公司网站http换成https

    看了博客园将近一年了,一直都只是在被动的看,总觉得应该写点什么,但是又不知道该写点什么.今天正好公司要把网站由http换成https,那我就顺便记录一下吧. 由于之前没有弄过,所以就面向百度编程. 首 ...

  7. 蛋疼zipline安装

    比安装zipline更让人蛋疼的是,网上的教程没有一个是TM对的,真的是忍不住要吐血. 真的是一步一坑,一步一坑 安装环境: Windows7旗舰版,64位系统 python 版本3.5.3 我没有用 ...

  8. uestc 1703一道更简单的字符串题目

    https://vjudge.net/problem/UESTC-1703 题意:略 思路: 枚举+字符串hash. ans从1到len开始枚举字符串的长度,然后就依次比较各段长度为ans的字符串的h ...

  9. Java-NIO(六):Channel聚集(gather)写入与分散(scatter)读取

    Channel聚集(gather)写入: 聚集写入( Gathering Writes)是指将多个 Buffer 中的数据“聚集”到 Channel. 特别注意:按照缓冲区的顺序,写入 positio ...

  10. 南阳OJ-91-阶乘之和---二进制枚举(入门)

    题目链接:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=91 题目大意: 给你一个非负数整数n,判断n是不是一些数(这些数不允许重复使用,且为 ...