习题:电压(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;
}

猜你喜欢

转载自www.cnblogs.com/loney-s/p/11741270.html
今日推荐