Summer training day6 codeforces19E 树链剖分,并查集
来源:互联网 发布:直销软件开发价格 编辑:程序博客网 时间:2024/06/07 00:09
Once upon a time there lived a good fairy A. One day a fine young man B came to her and asked to predict his future. The fairy looked into her magic ball and said that soon the fine young man will meet the most beautiful princess ever and will marry her. Then she drew on a sheet of paper n points and joined some of them with segments, each of the segments starts in some point and ends in some other point. Having drawn that picture, she asked the young man to erase one of the segments from the sheet. Then she tries to colour each point red or blue so, that there is no segment having points of the same colour as its ends. If she manages to do so, the prediction will come true. B wants to meet the most beautiful princess, that's why he asks you to help him. Find all the segments that will help him to meet the princess.
The first input line contains two integer numbers: n — amount of the drawn points and m — amount of the drawn segments (1 ≤ n ≤ 104, 0 ≤ m ≤ 104). The following m lines contain the descriptions of the segments. Each description contains two different space-separated integer numbers v, u (1 ≤ v ≤ n, 1 ≤ u ≤ n) — indexes of the points, joined by this segment. No segment is met in the description twice.
In the first line output number k — amount of the segments in the answer. In the second line output k space-separated numbers — indexes of these segments in ascending order. Each index should be output only once. Segments are numbered from 1 in the input order.
4 41 21 32 43 4
41 2 3 4
4 51 22 33 44 11 3
15
题解:
我们可以先构造一颗生成树,这颗生成树顶点上的涂色是固定的。然后我们开始处理剩下的边,对于两个顶点颜色相同的边,我们把它放到vectorA中,颜色不同的边放在vectorB当中。如果此时把vectorA中的边加入到生成树中,毫无疑问会产生奇数环,也就是说会产生矛盾。答案所需要的边有一个特点,那就是它一定会被所有的奇数环所包含。如果我们把vectorB中的边加入到生成树中的话,会产生偶数环。如果一条边被偶数环和所有的奇数环所包含,那么它一定不会是答案,因为把他去掉之后会在原来偶数环的基础上产生一个奇数环。
那么我们要找的边就非常清楚了,就是被所有奇数环包含且不被偶数环包含的边。
统计每条边被经过了多少次,借助树链剖分这个数据结构。
我们从vectorA中拿出一条边,把设置这条边的cost为-1。并把u,v链上所有的边都-1操作。
从vectorB中拿出一条比边,把这条边设置cost为1,并把u,v这条链上所有的边都+1操作。
然后统计所有的边,边权值等于vectorB.size()的就是答案。
在构造生成树的时候借助并查集这个数据结构。
代码:
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>using namespace std;const int MAXN = 1e5+7;int head[MAXN];int siz[MAXN],fa[MAXN],son[MAXN],dep[MAXN],top[MAXN],w[MAXN];int index;int cnt;int n;struct edge{ int v; int next; int cost; }Es[MAXN<<1]; struct segtree{int val[MAXN<<2];int mark[MAXN<<2];void init(){memset(val,0,sizeof(val));memset(mark,0,sizeof(val));}void pushup(int rt){val[rt] = val[rt*2] + val[rt*2+1];}void pushdown(int rt,int l,int r){if(mark[rt]){int mid = (l + r) / 2;val[rt*2] += mark[rt] * (mid - l + 1);val[rt*2+1] += mark[rt] * (r - mid);mark[rt*2] += mark[rt];mark[rt*2+1] += mark[rt];mark[rt] = 0;}}void update(int rt,int l,int r,int ul,int ur,int addval){if(l > ur || r < ul) return ;if(ul <= l && r <= ur) {val[rt] += addval * (r - l + 1);mark[rt] += addval;return ;}pushdown(rt,l,r);int mid = (l+r)/2;update(rt*2,l,mid,ul,ur,addval);update(rt*2+1,mid+1,r,ul,ur,addval);pushup(rt);}int query(int rt,int l,int r,int ul,int ur){if(l > ur || r < ul) return 0;if(ul <= l && r <= ur) {return val[rt];}pushdown(rt,l,r);int mid = (l+r)/2;int a = query(rt*2,l,mid,ul,ur);int b = query(rt*2+1,mid+1,r,ul,ur);return a + b;}}seg;void init(){ index = cnt = 0; memset(head,-1,sizeof(head)); seg.init();}inline void add_edge(int i,int j,int cost = 1){ Es[cnt].v = j; Es[cnt].cost = cost; Es[cnt].next = head[i]; head[i] = cnt++; } void dfs1(int u,int f,int _dep){son[u] = 0;fa[u] = f;dep[u] = _dep;siz[u] = 1;for(int e = head[u];e != -1;e = Es[e].next){int v = Es[e].v;if(v == fa[u]) continue;dfs1(v,u,_dep+1);siz[u] += siz[v];if(siz[v] > siz[son[u]])son[u] = v;}}void dfs2(int u,int tp){top[u] = tp;w[u] = ++index;if(son[u]) dfs2(son[u],tp);else return ;for(int e = head[u];e != -1;e = Es[e].next){int v = Es[e].v;if(v == son[u] || v == fa[u]) continue;dfs2(v,v);}}int getsum(int u,int v){int ans = 0;int fu = top[u],fv = top[v];while(fu != fv){if(dep[fu] < dep[fv]) /*确保fu在下面*/swap(fu,fv),swap(u,v);ans += seg.query(1,1,n,w[fu],w[u]);u = fa[fu];fu = top[u];}if(u == v) return ans;if(dep[u] < dep[v]) swap(u,v);ans += seg.query(1,1,n,w[son[v]],w[u]);return ans;}void modify(int u,int v,int addval){/*区间修改*/int fu = top[u],fv = top[v];while(fu != fv){if(dep[fu] < dep[fv]) /*确保fu在下面*/swap(fu,fv),swap(u,v);seg.update(1,1,n,w[fu],w[u],addval);u = fa[fu];fu = top[u];}if(u == v) return ;if(dep[u] < dep[v]) swap(u,v);seg.update(1,1,n,w[son[v]],w[u],addval);}int parent[MAXN];int find(int x){return x == parent[x] ? x : parent[x] = find(parent[x]);}void join(int x,int y){int px = find(x);int py = find(y);parent[px] = py;}int U[MAXN],V[MAXN],C[MAXN];int color[MAXN];int cost[MAXN];int m;void dfs(int u,int c){color[u] = c;for(int e = head[u];e != -1;e = Es[e].next){int v = Es[e].v;if(v != fa[u])dfs(v,c ^ 1);}}int main(){init();memset(color,-1,sizeof(color));for(int i = 0;i < MAXN;i++) parent[i] = i;scanf("%d%d",&n,&m);for(int i = 1;i <= m;i++){scanf("%d%d",&U[i],&V[i]); }vector<int> vec;for(int i = 1;i <= m;i++){if(find(U[i]) == find(V[i])){vec.push_back(i);}else{join(U[i],V[i]);add_edge(U[i],V[i]);add_edge(V[i],U[i]);}}for(int i = 1;i <= n;i++){if(!dep[i]) {dfs1(i,i,0);dfs2(i,i);dfs(i,0);}}int tmp = 0;for(int i = 0;i < vec.size();i++){int e = vec[i];if(color[U[e]] == color[V[e]]){modify(U[e],V[e],1);cost[e] = 1;tmp++;}else{modify(U[e],V[e],-10);cost[e] = -1;}}if(tmp == 0) {printf("%d\n",m);for(int i = 1;i <= m;i++){printf("%d ",i);}return 0;}vector<int> ans;for(int i = 1;i <= m;i++){if(cost[i]){if(cost[i] >= tmp) ans.push_back(i);}else if(getsum(U[i],V[i]) >= tmp){ans.push_back(i);}}printf("%d\n",ans.size());for(int i = 0;i < ans.size();i++){printf("%d ",ans[i]);}return 0;}
- Summer training day6 codeforces19E 树链剖分,并查集
- Summer Training day6 codeforces 593D LCA+并查集
- Summer Training day6 codeforces292D并查集合并
- Summer Training day6 codeforces633G 线段树、bitset
- Summer Training day6 coseforces339D 线段树、位操作
- Summer Training day6 codeforces240F 线段树、回文串
- Summer Training day6 codeforces787D 最短路spfa,线段树建图
- Summer Training day6 codeforces343D dfs序、线段树
- Summer Training day6 codeforces 675D 二叉搜索树
- SPOJ-IAPCR2F Summer Trip(dfs/并查集)
- UESTC summer training A 【树链剖分 模板】
- Training:并查集(最小生成树)
- Tri_integral Summer Training 6
- BUPT-SUMMER-TRAINING-搜索
- 2017 Summer Training Day1
- Summer Training day4 欧拉降幂
- Summer Training day4 Sumdiv
- After Summer Training.
- 编写windbg调试器扩展 入门篇2
- Sampled Softmax
- MVC三层架构简析
- 【bzoj3173】[Tjoi2013]最长上升子序列 Treap
- CodeForce 356A Knight Tournament(线段树的区间更新+单点询问)
- Summer training day6 codeforces19E 树链剖分,并查集
- 51nod-矩阵取数问题-【动态规划】
- 异常:编译时异常和运行时异常&throw和throws区别try-catch的应用
- 树链剖分
- 无数据库连接实现对数据的增删改查《图书管理系统》(附源代码)
- Java中的回调机制
- 【机器学习】关于CNN中1×1卷积核和Network in Network的理解
- 项目代码优化:使用Java枚举常量代替类常量
- 迭代器失效