习题:电压(LCA&树上差分)

题目

思路

首先对于对于高低电压,其实就是二染色问题
有了这个想法之后
自然就会想到图中的环的奇偶性
如何快速的判断呢?
笔者用的是建树+LCA的办法
之后,如果是奇环,环上的所有的边+1
如果是偶环,则-1
用树上差分的办法可以以 \(O(1)\)的优秀时间复杂度处理
之后判断每一个边的值是否为奇环的总数即可

代码

#include<iostream>
#include<vector>
#include<cstring>
#include<cstdio>
#include<map>
using namespace std;
int n,m;
int ans;
int cnt;
int depth[100005];
int c[100005];
int dp[100005][25];
int num;
map<int,bool> f[100005];
vector<int> g[100005];
vector<int> tre[100005];
bool vis[100005];
void read(int &x)
{
	x=0;
	char c=getchar();
	int f=1;
	while('0'>c||c>'9')
	{
		if(x=='-')
			f=-1;
		c=getchar();
	}
	while('0'<=c&&c<='9')
	{
		x=(x<<3)+(x<<1)+c-'0';
		c=getchar();
	}
	x*=f;
}
void write(int x)
{
	if(x<10)
	{
		putchar(x+'0');
	}
	else
	{
		write(x/10);
		putchar(x%10+'0');
	}
}
void dfs(int u,int fa)
{
	vis[u]=1;
	depth[u]=depth[fa]+1;
	dp[u][0]=fa;
	for(int i=1;i<=20;i++)
		dp[u][i]=dp[dp[u][i-1]][i-1];
	for(int i=0;i<g[u].size();i++)
	{
		int v=g[u][i];
		if(!vis[v])
		{
			tre[u].push_back(v);
			dfs(v,u);
		}
		else
			f[u][v]=1;
	}
}
void solve(int u)
{
	vis[u]=1;
	for(int i=0;i<tre[u].size();i++)
	{
		int v=tre[u][i];
		solve(v);
		c[u]+=c[v];
	}
	if(c[u]==num&&dp[u][0])
		ans++;
}
int lca(int u,int v)
{
	if(depth[u]>depth[v])
		swap(u,v);
	for(int i=20;i>=0;i--)
	{
		if(depth[dp[v][i]]>=depth[u])
			v=dp[v][i];
	}
	if(u==v)
		return u;
	for(int i=20;i>0;i--)
	{
		if(dp[u][i]!=dp[v][i])
		{
			u=dp[u][i];
			v=dp[v][i];
		}
		if(dp[u][0]==dp[v][0])
			return dp[u][0];
	}
	return dp[u][0];
}
int main()
{
	read(n);
	read(m);
	for(int i=1;i<=m;i++)
	{
		int s,e;
		read(s);
		read(e);
		g[s].push_back(e);
		g[e].push_back(s);
	}
	for(int i=1;i<=n;i++)
		if(!vis[i])
			dfs(i,0);
	for(int i=1;i<=n;i++)
	{
		vis[i]=0;
		for(int j=0;j<g[i].size();j++)
		{
			if(f[i][g[i][j]]&&f[g[i][j]][i])
			{
				int t=lca(i,g[i][j]);
				int s=depth[i]+depth[g[i][j]];
				if(s%2)
				{
					c[t]+=2;
					c[i]--;
					c[g[i][j]]--;
				}
				else
				{
					c[i]++;
					c[g[i][j]]++;
					c[t]-=2;
					num++;
				}
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(!vis[i])
		{
			solve(i);
		}
	}
	if(num==2)
                ans++;
	write(ans);
	return 0;
}

posted @ 2019-10-25 22:47  loney_s  阅读(225)  评论(0)    收藏  举报