【HDU】5458 Stability(2015 ACM/ICPC Shenyang Online)
2016-07-10 20:23
411 查看
Stability
题目链接
Stability题目大意
给你一个图,现在有一系列操作,会删去一些边,然后问你从a到b有几条边是删去之后a和b就不联通了。(题中的Stability)题解
数链剖分
假设从a到b有环,a到b的查询肯定是0。因为删掉任何一条边a和b,a和b还是相连的,但是只要a跟b没有环。a到b则至少有一条边是满足题意的(至少一条的意思是a到b的路径中可能有其他的边在环中),题目中说最后的图也是连通的,如此分析,我们可以想到建一颗树,然后在树上查询。下面写具体做法:删掉边会破坏环,所以在这一题中为了方便处理,我们把询问和删除操作倒过来处理。我们首先把要删除的边从图中全都删去,然后建一颗树,所有的边权设为1,因为最后可能是图,所以我们把多余的边(成环的边)所成的环的权值全部设为0,在树上看其实就是把从a到b的一条路径全部设置为0了,然后我们从操作的最后开始,查询ab实际上就是查询a到b的边权和,插入ab实际上就是把ab的路径边全设为0。最后输出就行了。
查询和插入用数链剖分离线处理。
代码
代码略长。#include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <set> #include <map> using namespace std; struct question { int a,b,c; }; question que[100005]; struct tree { int l,r,val; bool f; }; tree d[120005]; multiset< pair<int,int> > S,V; multiset< pair<int,int> >::iterator it; int T,n,m,q,num; int father[50005],top[50005],fat[50005],pos[50005],son[50005],siz[50005],dep[50005],rpos[50005]; vector<int> G[50005],A; int findfather(int k) { if (father[k]==k) return k; else return father[k]=findfather(father[k]); } void dfs(int u,int F,int depth) { siz[u]=1; fat[u]=F; dep[u]=depth; son[u]=0; for (int i=0;i<G[u].size();i++) { int v=G[u][i]; if (v!=F) { dfs(v,u,depth+1); siz[u]+=siz[v]; if (siz[v]>siz[son[u]]) son[u]=v; } } } void tcp(int u,int t) { pos[u]=num++; rpos[num-1]=u; top[u]=t; if (son[u]) tcp(son[u],t); for (int i=0;i<G[u].size();i++) { int v=G[u][i]; if (v!=fat[u] && v!=son[u]) tcp(v,v); } } void buildtree(int n,int l,int r) { d .l=l; d .r=r; d .val=0; d .f=0; if (l==r) { d .val=1; return ; } int mid=(l+r)>>1; buildtree(n*2,l,mid); buildtree(n*2+1,mid+1,r); d .val=d[n*2].val+d[n*2+1].val; } int Count(int n,int l,int r) { if (d .f) return 0; if (d .l==l && d .r==r) return d .val; int mid=(d .l+d .r)>>1; if (r<=mid) return Count(n*2,l,r); else if (l>mid) return Count(n*2+1,l,r); else return Count(n*2,l,mid)+Count(n*2+1,mid+1,r); } void Insert(int n,int l,int r) { if (d .f) return ; if (d .l==l && r==d .r) { d .f=1; d .val=0; return ; } int mid=(d .l+d .r)>>1; if (r<=mid) Insert(n<<1,l,r); else if (l>mid) Insert(n<<1|1,l,r); else { Insert(n<<1,l,mid); Insert(n<<1|1,mid+1,r); } d .val=d[n*2].val+d[n*2+1].val; } void solve(int u,int v) { int topu=top[u],topv=top[v]; while (topv!=topu) { if (dep[topu]<dep[topv]) { swap(u,v); swap(topu,topv); } Insert(1,pos[topu],pos[u]); u=fat[topu]; topu=top[u]; } if (u==v) return ; else { if (dep[u]>dep[v]) swap(u,v); Insert(1,pos[son[u]],pos[v]); } } int answer(int u,int v) { int ans=0; int topu=top[u],topv=top[v]; while (topv!=topu) { if (dep[topu]<dep[topv]) { swap(u,v); swap(topu,topv); } ans+=Count(1,pos[topu],pos[u]); u=fat[topu]; topu=top[u]; } if (u==v) return ans; else { if (dep[u]>dep[v]) swap(u,v); ans+=Count(1,pos[son[u]],pos[v]); } return ans; } int main() { int Case=1; scanf("%d",&T); while (T--) { int u,v; S.clear(); num=0; V.clear(); memset(father,0,sizeof(father)); memset(que,0,sizeof(que)); memset(siz,0,sizeof(siz)); memset(son,0,sizeof(son)); memset(dep,0,sizeof(dep)); memset(top,0,sizeof(top)); memset(pos,0,sizeof(pos)); memset(rpos,0,sizeof(rpos)); memset(d,0,sizeof(d)); memset(fat,0,sizeof(fat)); for (int i=0;i<=100000;i++) G[i].clear(); A.clear(); scanf("%d%d%d",&n,&m,&q); for (int i=0;i<=n;i++) father[i]=i; for (int i=0;i<m;i++) { scanf("%d%d",&u,&v); if (u>v) swap(u,v); S.insert(pair<int,int> (u,v) ); } for (int i=0;i<q;i++) { scanf("%d%d%d",&que[i].a,&que[i].b,&que[i].c); if (que[i].b>que[i].c) swap(que[i].b,que[i].c); if (que[i].a==1) S.erase( S.find(pair<int,int> (que[i].b,que[i].c)) ); } for (it=S.begin();it!=S.end();it++) { int F1=it->first,F2=it->second; int f1=findfather(F1),f2=findfather(F2); if (f1!=f2) { V.insert(*it); if (f1>f2) swap(f1,f2); father[f2]=f1; G[F1].push_back(F2); G[F2].push_back(F1); } } dfs(1,0,0); tcp(1,1); buildtree(1,0,num-1); for (it=S.begin();it!=S.end();it++) if (V.find(*it)==V.end()) { int F1=it->first,F2=it->second; solve(F1,F2); } for (int i=q-1;i>=0;i--) { int a=que[i].a,b=que[i].b,c=que[i].c; if (a==1) solve(b,c); else if (a==2) A.push_back(answer(b,c)); } printf("Case #%d:\n",Case++); for (int i=A.size()-1;i>=0;i--) printf("%d\n",A[i]); } return 0; }
相关文章推荐
- ZERO
- 无线网覆盖问题 NYOJ 199
- 并查集的学习
- Rails的事务和锁
- 在notepad++ 汉化
- 文章标题
- 从指定范围获取指定个数的正序排列的不重复随机数
- 文章标题
- 元数据(metadata)
- linux关于readlink函数获取运行路径的小程序
- The Skyline Problem
- 数据结构之栈
- 【闲谈】应聘时要问HR的7个问题
- Hdu 5323 Solve this interesting problem(搜索)
- HDU 1054 Strategic Game (二分图最小点覆盖)
- 在类定义时指定泛型的上限
- NYOJ 62笨小熊问题
- uva 12034 比赛排名
- get与post乱码过滤器
- Java线程(学习整理)--3--简单的死锁例子