hdu 5458 Stability(树链剖分+并查集)
Stability
Time Limit: 3000/2000 MS (Java/Others) Memory Limit: 65535/102400 K (Java/Others)
Total Submission(s): 1347 Accepted Submission(s): 319
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.
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.
Then for each query, print one line containing the stability between corresponding pair of nodes.
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
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(树链剖分+并查集)的更多相关文章
- HDU 5458 Stability (树链剖分+并查集+set)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5458 给你n个点,m条边,q个操作,操作1是删边,操作2是问u到v之间的割边有多少条. 这题要倒着做才 ...
- bzoj3694: 最短路(树链剖分/并查集)
bzoj1576的帮我们跑好最短路版本23333(双倍经验!嘿嘿嘿 这题可以用树链剖分或并查集写.树链剖分非常显然,并查集的写法比较妙,涨了个姿势,原来并查集的路径压缩还能这么用... 首先对于不在最 ...
- [BZOJ2238]Mst 最小生成树+树链剖分/并查集
链接 题解 先构建出最小生成树,如果删的是非树边,直接输出答案 否则问题转化为,把该边删掉后剩下两个联通块,两个端点分别在两个块内的最小边权,LCT可以维护 不妨换一种思考方向:考虑一条非树边可以代替 ...
- HDU 5044 (树链剖分+树状数组+点/边改查)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5044 题目大意:修改链上点,修改链上的边.查询所有点,查询所有边. 解题思路: 2014上海网赛的变 ...
- HDU 3966(树链剖分+点修改+点查询)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 题目大意:营地的分布成树型.每个营地都有一些人,每次修改修改一条链上的所有营地的人数,每次查询单 ...
- HDU 5044 Tree --树链剖分
题意:给一棵树,两种操作: ADD1: 给u-v路径上所有点加上值k, ADD2:给u-v路径上所有边加上k,初始值都为0,问最后每个点和每条边的值,输出. 解法:树链剖分可做,剖出来如果直接用线段树 ...
- HDU - 3966-Aragorn' Story(树链剖分+线段树)
链接:https://vjudge.net/problem/HDU-3966 题意: Our protagonist is the handsome human prince Aragorn come ...
- HDU 3966 RE 树链剖分 线段树 Aragorn's Story
题意: 给出一棵树,每个顶点上有一个权值. 操作:选择一条路径,并将路径上所有的点的权值同时加或减某个数. 查询:某个点的当前权值 分析: 树链剖分完毕后,就是简单的线段树区间更新. 提交的时候注意要 ...
- HDU 5242 利用树链剖分思想进行贪心
题目大意: 在给定带权值节点的树上从1开始不回头走到某个底端点后得到所有经过的点的权值后,这些点权值修改为0,到达底部后重新回到1,继续走,问走k次,最多能得到多少权值之和 这其实就是相当于每一次都走 ...
随机推荐
- nyoj 数的长度
描述 N!阶乘是一个非常大的数,大家都知道计算公式是N!=N*(N-1)······*2*1.现在你的任务是计算出N!的位数有多少(十进制)? 输入 首行输入n,表示有多少组测试数据(n<1 ...
- Browser Object Model
BOM:浏览器提供的一系列对象 window对象是BOM最顶层对象 * 计时器setInterval(函数,时间)设置计时器 时间以毫秒为单位 clearInterval(timer) 暂停计时器se ...
- 07_Python的控制判断循环语句1(if判断,for循环...)_Python编程之路
Python的数据类型在前几节我们都简单的一一介绍了,接下来我们就要讲到Python的控制判断循环语句 在现实编程中,我们往往要利用计算机帮我们做大量重复计算的工作,在这样的情况下,需要机器能对某个条 ...
- Mego开发文档 - 数据属性生成值
数据属性生成值 该功能用于在数据插入或更新时为指定属性生成期望的值,Mego提供了非常灵活的实现方式以满足各种数据提交时的自动赋值问题. 生成值目的及模式 在Mego中生成值的目的一定是插入数据或更新 ...
- JAVA 中一个非常轻量级只有 200k 左右的 RESTful 路由框架
ICEREST 是一个非常轻量级只有 200k 左右的 RESTful 路由框架,通过 ICEREST 你可以处理 url 的解析,数据的封装, Json 的输出,和传统的方法融合,请求的参数便是方法 ...
- GIT入门笔记(19)GIT 小结
1.add和commit为什么Git添加文件需要add,commit一共两步呢?因为commit可以一次提交很多文件,所以你可以多次add不同的文件,比如:$ git add file1.txt$ g ...
- 十个你需要在 PHP 7 中避免的坑
1. 不要使用 mysql_ 类函数 终于,你不用再看到建议不要使用 mysql_ 函数的提示了.因为 PHP 7 从核心上完全移除了它们,这意味着请你移步至更好的 mysqli_ 类函数,或者更灵活 ...
- 浅谈 DML、DDL、DCL的区别
一.DML DML(data manipulation language)数据操纵语言: 就是我们最经常用到的 SELECT.UPDATE.INSERT.DELETE. 主要用来对数据库的数据进行一些 ...
- 框架学习笔记之Mybatis(二)
一.动态sql 通过mybatis提供的标签,实现sql语句的拼接. 1.where <select id="findUserList" parameterType=&quo ...
- C#在使用Assembly加载程序集时失败
错误现象: 进行插件读取时出现错误:"尝试从一个网络位置加载程序集,在早期版本的 .NET Framework 中,这会导致对该程序集进行沙盒处理.此发行版的 .NET Framework ...