HDU 5458 Stability

Stability

Time Limit: 2000ms

Memory Limit: 102400KB

This problem will be judged on HDU. Original ID: 5458
64-bit integer IO format: %I64d      Java class name: Main

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 1 to 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

Source
2015 ACM/ICPC Asia Regional Shenyang Online

解题:树链剖分

逆向操作,把删边视为加边,除去删除的那些边,玩树链剖分,首先,你得有棵树,没树,什么都是扯淡。

我们把要删的那些边从图上统统删除,剩下的残图不一定就是树,所以用并查集在残图上找棵树,树的边权都设为1,然后把残图中不在树上的边都加到树上,这样形成环了,那么把环上的树边全部置0.

现在开始删边(实际是加边,因为逆序操作)和查询,是的,逆序的,每次加边,就把形成的环,环上的树边都置成0,查询就查询这条路径上的边权和即可

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <set>
  4 #include <algorithm>
  5 #include <cstring>
  6 using namespace std;
  7 typedef pair<int,int> PII;
  8 const int maxn = 200010;
  9 struct arc {
 10     int to,next;
 11     arc(int x = 0,int y = -1) {
 12         to = x;
 13         next = y;
 14     }
 15 } e[maxn<<1];
 16 struct node {
 17     int lt,rt,sum,lazy;
 18 } tree[maxn<<2];
 19 int head[maxn],tot;
 20 void add(int u,int v) {
 21     e[tot] = arc(v,head[u]);
 22     head[u] = tot++;
 23 }
 24 inline void pushup(int v) {
 25     tree[v].sum = tree[v<<1].sum + tree[v<<1|1].sum;
 26 }
 27 inline void pushdown(int v) {
 28     if(~tree[v].lazy) {
 29         tree[v<<1].sum = (tree[v<<1].rt - tree[v<<1].lt + 1)*tree[v].lazy;
 30         tree[v<<1].lazy = tree[v].lazy;
 31         tree[v<<1|1].sum = (tree[v<<1|1].rt - tree[v<<1|1].lt + 1)*tree[v].lazy;
 32         tree[v<<1|1].lazy = tree[v].lazy;
 33         tree[v].lazy = -1;
 34     }
 35 }
 36 void build(int lt,int rt,int v) {
 37     tree[v].lt = lt;
 38     tree[v].rt = rt;
 39     tree[v].lazy = -1;
 40     if(lt == rt) {
 41         tree[v].sum = 1;
 42         return;
 43     }
 44     int mid = (lt + rt)>>1;
 45     build(lt,mid,v<<1);
 46     build(mid + 1,rt,v<<1|1);
 47     pushup(v);
 48 }
 49 void update(int lt,int rt,int val,int v) {
 50     if(lt <= tree[v].lt && rt >= tree[v].rt) {
 51         tree[v].sum = (tree[v].rt - tree[v].lt + 1)*val;
 52         tree[v].lazy = val;
 53         return;
 54     }
 55     pushdown(v);
 56     if(lt <= tree[v<<1].rt) update(lt,rt,val,v<<1);
 57     if(rt >= tree[v<<1|1].lt) update(lt,rt,val,v<<1|1);
 58     pushup(v);
 59 }
 60 int query(int lt,int rt,int v) {
 61     if(lt == tree[v].lt && rt == tree[v].rt) return tree[v].sum;
 62     pushdown(v);
 63     int mid = (tree[v].lt + tree[v].rt)>>1;
 64     if(rt <= mid) return query(lt,rt,v<<1);
 65     if(lt > mid) return query(lt,rt,v<<1|1);
 66     return query(lt,mid,v<<1) + query(mid + 1,rt,v<<1|1);
 67 }
 68 int fa[maxn],dep[maxn],top[maxn],siz[maxn],son[maxn],loc[maxn],cnt;
 69 void FindHeavyEdge(int u,int father,int depth) {
 70     fa[u] = father;
 71     dep[u] = depth;
 72     siz[u] = 1;
 73     son[u] = -1;
 74     for(int i = head[u]; ~i; i = e[i].next) {
 75         if(e[i].to == father) continue;
 76         FindHeavyEdge(e[i].to,u,depth + 1);
 77         siz[u] += siz[e[i].to];
 78         if(son[u] == -1 || siz[son[u]] < siz[e[i].to])
 79             son[u] = e[i].to;
 80     }
 81 }
 82 void ConnectHeavyEdge(int u,int ancestor) {
 83     top[u] = ancestor;
 84     loc[u] = ++cnt;
 85     if(son[u] != -1) ConnectHeavyEdge(son[u],ancestor);
 86     for(int i = head[u]; ~i; i = e[i].next) {
 87         if(e[i].to == fa[u] || e[i].to == son[u]) continue;
 88         ConnectHeavyEdge(e[i].to,e[i].to);
 89     }
 90 }
 91 void UPDATE(int u,int v,int val = 0) {
 92     while(top[u] != top[v]) {
 93         if(dep[top[u]] < dep[top[v]]) swap(u,v);
 94         update(loc[top[u]],loc[u],val,1);
 95         u = fa[top[u]];
 96     }
 97     if(u == v) return;
 98     if(dep[u] > dep[v]) swap(u,v);
 99     update(loc[son[u]],loc[v],val,1);
100 }
101 int QUERY(int u,int v,int ret = 0) {
102     while(top[u] != top[v]) {
103         if(dep[top[u]] < dep[top[v]]) swap(u,v);
104         ret += query(loc[top[u]],loc[u],1);
105         u = fa[top[u]];
106     }
107     if(u == v) return ret;
108     if(dep[u] > dep[v]) swap(u,v);
109     return ret + query(loc[son[u]],loc[v],1);
110 }
111 int u,v,ans[maxn],uf[maxn],op[maxn],x[maxn],y[maxn];
112 bool used[maxn];
113 int Find(int x) {
114     if(x != uf[x]) uf[x] = Find(uf[x]);
115     return uf[x];
116 }
117 multiset<PII>S,V;
118 int main() {
119     int kase,n,m,q,cs = 1;
120     scanf("%d",&kase);
121     while(kase--) {
122         S.clear();
123         V.clear();
124         scanf("%d%d%d",&n,&m,&q);
125         for(int i = tot = cnt = 0; i < m; ++i) {
126             scanf("%d%d",&u,&v);
127             if(u > v) swap(u,v);
128             S.insert(PII(u,v));
129         }
130         for(int i = 0; i <= n; ++i) {
131             head[i] = -1;
132             used[i] = false;
133             uf[i] = i;
134         }
135         for(int i = 0; i < q; ++i) {
136             scanf("%d%d%d",op + i,x + i,y + i);
137             if(x[i] > y[i]) swap(x[i],y[i]);
138             if(op[i] == 1) S.erase(S.find(PII(x[i],y[i])));
139         }
140         for(auto &it:S) {
141             int a = Find(it.first),b = Find(it.second);
142             if(a != b) {
143                 V.insert(it);
144                 add(it.first,it.second);
145                 add(it.second,it.first);
146                 uf[a] = b;
147             }
148         }
149         FindHeavyEdge(1,0,0);
150         ConnectHeavyEdge(1,1);
151         build(1,cnt,1);
152         for(auto &it:S)
153             if(V.find(it) == V.end()) UPDATE(it.first,it.second);
154         for(int i = q-1; i >= 0; --i)
155             if(op[i] == 1) UPDATE(x[i],y[i]);
156             else if(op[i] == 2) ans[i] = QUERY(x[i],y[i]);
157         printf("Case #%d:\n",cs++);
158         for(int i = 0; i < q; ++i)
159             if(op[i] == 2) printf("%d\n",ans[i]);
160     }
161     return 0;
162 }

时间: 2024-11-25 22:29:00

HDU 5458 Stability的相关文章

Hdu 5458 Stability (LCA + 并查集 + 树状数组 + 缩点)

题目链接: Hdu 5458 Stability 题目描述: 给出一个还有环和重边的图G,对图G有两种操作: 1 u v, 删除u与v之间的一天边 (保证这个边一定存在) 2 u v, 查询u到v的路径上有几条桥. 解题思路: 这个题目有很多次操作,包含查询和删边两类,首先想到的是连通分量加缩点.如果按照顺序来,删边时候求桥就是问题了.所以可以离线处理,然后一边记录答案一边加边缩点. 对于一个图,把连通分量缩成一个点后,这个图就成为了一棵树, 然后深度差就等于桥的数目.查询的时候对于(u, v)

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 Problem Description Given an undirected connected graph G with n nodes and m edges, with possibly r

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

题目链接: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的割边个数的

HDU 5458 Stability(双连通分量+LCA+并查集+树状数组)(2015 ACM/ICPC Asia Regional Shenyang Online)

题目大意:给一个N个点M条边的无向图,有Q个询问:1.删掉a.b之间所存在的边:2.询问有多少条边,单独删掉之后a与b不再连通. 思路:脑洞大开. 对于询问,首先想到的就是a与b之间有多少桥(割边),然后想到双连通分量,然而删边是个坑爹的问题,于是我们离线倒着来,把删边变成加边. 双连通分量这种东西呢,其实缩点连起来之后,就是一棵树辣. 然后询问两个点的时候,设根到点x的距离为dep[x],a.b的最近公共祖先为lca(a, b),那么询问query(a, b) = dep[a] + dep[b

HDU 4569 Special equations(取模)

Special equations Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4569 Description Let f(x) = a nx n +...+ a 1x +a 0, in which a i (0 <= i <= n) are all known integers. We call f(x) 0 (mod

HDU 6203 ping ping ping [LCA,贪心,DFS序,BIT(树状数组)]

题目链接:[http://acm.hdu.edu.cn/showproblem.php?pid=6203] 题意 :给出一棵树,如果(a,b)路径上有坏点,那么(a,b)之间不联通,给出一些不联通的点对,然后判断最少有多少个坏点. 题解 :求每个点对的LCA,然后根据LCA的深度排序.从LCA最深的点对开始,如果a或者b点已经有点被标记了,那么continue,否者标记(a,b)LCA的子树每个顶点加1. #include<Bits/stdc++.h> using namespace std;

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include

hdu 1207 汉诺塔II (DP+递推)

汉诺塔II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4529    Accepted Submission(s): 2231 Problem Description 经典的汉诺塔问题经常作为一个递归的经典例题存在.可能有人并不知道汉诺塔问题的典故.汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往

[hdu 2102]bfs+注意INF

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2102 感觉这个题非常水,结果一直WA,最后发现居然是0x3f3f3f3f不够大导致的--把INF改成INF+INF就过了. #include<bits/stdc++.h> using namespace std; bool vis[2][15][15]; char s[2][15][15]; const int INF=0x3f3f3f3f; const int fx[]={0,0,1,-1};