您的位置:首页 > 其它

【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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: