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. 201621123050 《Java程序设计》第8周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 2. 书面作业 1. ArrayList代码分析 1.1 解释ArrayList的contains源代码 答:ArrayLi ...

  2. 冲刺NO.5

    Alpha冲刺第五天 站立式会议 项目进展 今日项目完成内容主要包括了JS的学习,事务管理员模块与学生模块的完善与补充,并且开始编写信用信息管理模块和奖惩事务管理模块. 问题困难 前端部分的技术掌握的 ...

  3. C程序第二次作业

    2-1删除字符串中数字字符 1.设计思路 (1)主要描述题目算法 第一步:遍历指针s所指的s数组. 第二步:如果 * (s+i)在0至9之间的话,则跳过此 * (s+i). 第三步:如果* (s+i) ...

  4. 20162328蔡文琛week07

    学号 2016-2017-2 <程序设计与数据结构>第X周学习总结 教材学习内容总结 多态引用在不同的时候可以指向不同类型的对象. 多态引用在运行时才将方法调用用于它的定义绑定在一起. 引 ...

  5. 【审核】检查iOS项目中是否使用了IDFA

    (1)什么是IDFA 关于IDFA,在提交应用到App Store时,iTunes Connect有如下说明: 这里说到检查项目中是否包含IDFA,那如何来对iOS项目(包括第三方SDK)检查是否包含 ...

  6. iOS开发-继承特征详解

    面向对象的三大特性:封装,继承,多态. 1.继承 继承既能保证类的完整,又能简化代码. 把公共的方法和实例变量写在子类,子类只需要写父类独有的实例变量和方法即可. 继承是面向对象三大特性之一,合理的继 ...

  7. Flask 扩展 Flask-PyMongo

    安装 pip install Flask-PyMongo 初始化Pymongo实例 from flask import Flask from flask.ext.pymongo import PyMo ...

  8. 关于java中的数组

    前言:最近刚刚看完了<Java编程思想>中关于数组的一章,所有关于Java数组的知识,应该算是了解的差不多了.在此再梳理一遍,以便以后遇到模糊的知识,方便查阅. Java中持有对象的方式, ...

  9. MobileNet_v2

    研究动机: 神经网络彻底改变了机器智能的许多领域,实现了超人的准确性.然而,提高准确性的驱动力往往需要付出代价:现代先进网络需要高度计算资源,超出许多移动和嵌入式应用的能力. 主要贡献: 发明了一个新 ...

  10. css3动画transition详解

    一.transition-property 语法: transition-property : none | all | [ <IDENT> ] [ ',' <IDENT> ] ...