hdu 6200 mustedge mustedge mustedge

Problem Description
Give an connected undirected graph with  n  nodes and  m  edges, ( n,m105 ) which has no selfloops or multiple edges  initially
Now we have  q  operations ( q105 ): 
  
1 u v : add an undirected edge from  u  to  v (uv&&1u,vn)
2 u v : count the number of  mustedges  from  u  to  v (1u,vn) .

mustedge : we define set  Ei  as a path from  u  to  v  which contain edges in this path, and  |k1Ei|  is the number of  mustedges |x|  means size of set  x , and  E1,E2Ek  means all the paths.
It's guaranteed that  n,m,q106
Please note that maybe there are more than one edges between two nodes after we add edges. They are not the same, which means they can be in a set at the same time. Read the sample data for more information.
 

Input
Input starts with an integer  T , denoting the number of test cases.
For each case:
First line are two number  n  and  m ;
Then next  m  lines, each contains two integers  u  and  v , which indicates an undirected edge from  u  to  v ;
Next line contains a number  q , the number of operations;
Then next  q  lines, contains three integers  x u  and  v  where  x  is the operation type, which describes an operation.

 

Output
For each test case, output "Case #x:" where  x  is the test case number starting from 1.
In each test case, print a single number one line when query the number of  mustedges .
 

Sample Input
  
  
2 4 3 1 2 2 3 3 4 5 2 1 4 1 2 3 2 1 4 2 2 3 2 2 4 8 9 1 2 2 3 1 3 3 4 4 5 4 6 5 7 5 8 7 8 5 2 7 8 2 1 6 2 4 7 1 6 8 2 5 6
 

Sample Output
  
  
Case #1: 3 2 0 1 Case #2: 0 2 1 0
 

Source


赛场上想到了树剖的方法,听说过不去就没有写

这题单log的做法是并查集+LCA+树状数组

我们先预处理出一棵生成树

假设加的边为(u,v)

那么我们找到u,v的LCA x

将u到x和v到x两条链上的边给标记

每次标记的时候把子树的深度减1

然后用并查集维护标记过的边的集合,这样每条边都只会被标记一遍

查询答案(u,v)的时候就是dep[u]+dep[v]-dep[x]*2,其中x是u,v的LCA

稍微有点卡常,找LCA的地方建议用树剖来写

因为边集和点集是同一个数量级

所以不建议先缩点再进行操作

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
inline char nc(){
   // static char buf[6000000],*p1=buf,*p2=buf;
  //  return p1==p2&&(p2=(p1=buf)+fread(buf,1,6000000,stdin),p1==p2)?EOF:*p1++;
    return getchar();
}
inline int read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
    //int x;
    //scanf("%d",&x);
    //return x;
}
struct line
{
     int s,t;
     int next;
}a[200001];
int edge,exedge;
int head[100001];
int scc,cnt;
bool v[100001];
int s[100001],topx;
int fa[100001];
inline void add(int s,int t)
{
	 a[edge].next=head[s];
     head[s]=edge;
     a[edge].s=s;
     a[edge].t=t;
}
int tot;
int ld[100001],rd[100001];
int fax[100001];
int dep[100001],son[100001];
int top[100001],w[100001];
int lson[100001]/*最大节点位置*/,mson[100001]/*最大节点值*/;
inline void dfs1(int d)
{
	v[d]=true;
	mson[d]=0;
	son[d]=0;
	int i;
	for(i=head[d];i!=0;i=a[i].next)
	{
		int t=a[i].t;
		if(!v[t])
		{
			dep[t]=dep[d]+1;
			fa[t]=d;
			dfs1(t);
			son[d]+=son[t]+1;
			if(son[t]>=mson[d])
			{
				mson[d]=son[t];
				lson[d]=t;
			}
		}
	}
}
inline void dfs2(int d)//先dfs重链 
{
	v[d]=true;
	tot++;
	w[tot]=d;
	ld[d]=tot;
	int i;
	for(i=head[d];i!=0;i=a[i].next)
	{
		int t=a[i].t;
		if(t==lson[d]&&!v[t])
		{
			top[t]=top[d];
			dfs2(t);
		}
	}
	for(i=head[d];i!=0;i=a[i].next)
	{
		int t=a[i].t;
		if(!v[t]&&t!=lson[d])
		{
			top[t]=t;
			dfs2(t);
		}
	}
	rd[d]=tot;
}
inline int lca(int s,int t)//深的那个点往当前链的top跳 
{
	int u=top[s],v=top[t];
	while(u!=v)
	{
		if(dep[u]>dep[v])
			s=fa[top[s]];
		else
			t=fa[top[t]];
		u=top[s];
		v=top[t];
	}
	if(ld[s]<ld[t])
		return s;
	else
		return t;
}
int tr[100005];
inline int lowbit(int x)
{
	return x&(-x);
}
inline void addx(int x,int xx)
{
	int i;
	for(i=x;i<=n;i+=lowbit(i))
		tr[i]+=xx;
}
inline int ask(int x)
{
	int i,sum=0;
	for(i=x;i>=1;i-=lowbit(i))
		sum+=tr[i];
	return sum;
}
inline int findx(int x)
{
	if(fax[x]!=x)
		fax[x]=findx(fax[x]);
	return fax[x];
}
inline void change(int s,int t)
{
	s=findx(s);
	int lx=fa[s];
	while(dep[lx]>=dep[t])
	{
		addx(ld[s],-1);
		addx(rd[s]+1,1);
		//fa[s]=lx;
		fax[s]=lx;
		s=findx(lx);
		lx=fa[s];
	//	assert(s!=lx);
	}
}
int ss[100001],tt[100001];
bool vv[100001];
int main()
{
	//freopen("1007.in","r",stdin);
//	freopen("1007.out","w",stdout);
	int T,kk=0;
	//scanf("%d",&T);
	T=read();
	while(T>0)
	{
		kk++;
		T--;
		int m;
		//scanf("%d%d",&n,&m);
	//	assert(T>=5);
		n=read();
		m=read();
		int i;
		int s,t;
		edge=0;
		memset(head,0,sizeof(head));
		for(i=1;i<=m;i++)
		{
			//scanf("%d%d",&s,&t);
			ss[i]=read();
			tt[i]=read(); 
		}
		for(i=1;i<=n;i++)
			fax[i]=i;
		int sum=0;
		memset(vv,false,sizeof(vv));
		for(i=1;i<=m;i++)
		{
			int fx=findx(ss[i]),fy=findx(tt[i]);
			if(fx!=fy)
			{
				sum++;
				fax[fx]=fy;
				edge++;
				add(ss[i],tt[i]);
				edge++;
				add(tt[i],ss[i]);
				vv[i]=true;
				if(sum==n-1)
					break;
			}
		}
		tot=0;
		memset(v,false,sizeof(v));
		memset(fa,0,sizeof(fa));
		dep[1]=1;
		dfs1(1);
		memset(v,false,sizeof(v));
		dfs2(1);
		memset(tr,0,sizeof(tr));
		for(i=1;i<=n;i++)
			fax[i]=i;
		for(i=1;i<=m;i++)
		{
			if(!vv[i])
			{
				int lx=lca(ss[i],tt[i]);
				change(ss[i],lx);
				change(tt[i],lx);
			}
		}
		int q;
		//scanf("%d",&q);
		q=read();
		int x;
		printf("Case #%d:\n",kk);
		for(i=1;i<=q;i++)
		{
			//scanf("%d%d%d",&x,&s,&t);
			x=read();
			s=read();
			t=read(); 
			if(x==1)
			{
				int lx=lca(s,t);
				change(s,lx);
				change(t,lx);
			}
			else
			{
 				int lx=lca(s,t);
				int dep1=dep[lx]+ask(ld[lx]);
				int dep2=dep[s]+ask(ld[s]);
				int dep3=dep[t]+ask(ld[t]);
				printf("%d\n",dep2+dep3-dep1*2);
			}
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值