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

原文地址:https://www.cnblogs.com/loney-s/p/11741270.html

时间: 2024-11-09 00:38:29

习题:电压(LCA&树上差分)的相关文章

NOIp2015 运输计划 [LCA] [树上差分] [二分答案]

我太懒了 吃掉了题面 题解 & 吐槽 一道很好的树上差分练习题. 不加fread勉强a过bzoj和luogu的数据,加了fread才能在uoj里卡过去. 可以发现,答案则是运输计划里花费的最大值,最大值最小,便是二分答案的标志. 那么该怎么check呢... 我们得找出所有超过限制的计划,这个过程可以在LCA倍增的过程中预处理出来. 然后再找出一些被这些计划都覆盖的边,找到最大的那条边,如果最大的计划花费减去最大的那条边小于x,那么x就是可行的. 但是该怎么找到那些被计划都覆盖的边呢... 我们

【洛谷】【lca+树上差分】P3258 [JLOI2014]松鼠的新家

[题目描述:] 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n(2 ≤ n ≤ 300000)个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家.可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞.可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃. 维尼是个馋家伙,立马就

POJ - 3417 Network (LCA+树上差分)

题目传送门:POJ - 3417 Network 题目大意: 存在一棵n个结点的树,加入m条新边,现在要让这个图不连通,你可以切断两条边,要求切断一条原边,一条新边,求切割的方案数. 分析: 加入m条新边,假设加入新边(u,v),那么u-->lca(u,v)-->v-->u形成一个环,此时可以切断新边,和环上任意的一条原边就可以使图不连通. 可以发现若加入一条新边,给环上的计数1,表示该边被一个环覆盖,树上有些边会被多个环覆盖,此时可以分情况讨论. 1.若该边被覆盖次数是0,则断掉该边后

P2680 运输计划[二分+LCA+树上差分]

题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n?1 条双向航道,每条航道建立在两个星球之间,这 n-1n?1 条航道连通了 LL 国的所有星球. 小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 u_i*u**i* 号星球沿最快的宇航路径飞行到 v_i*v**i* 号星球去.显然,飞船驶过一条航道是需要时间的,对于航道 jj,任意飞船驶过它所花费的时间为 t_j*t**j*,并且任意两艘飞船之间不会产生任

bzoj4390: [Usaco2015 dec]Max Flow(LCA+树上差分)

题目大意:给出一棵树,n(n<=5w)个节点,k(k<=10w)次修改,每次给定s和t,把s到t的路径上的点权+1,问k次操作后最大点权. 对于每次修改,给s和t的点权+1,给lca(s,t)和lca(s,t)的父亲的点权-1,每一个点的权就是它与它的子树权和,实际上就是树上的差分,又涨姿势了... 代码如下: uses math; type point=^rec; rec=record data:longint; next:point; end; var n,m,x,y,i,ans,fa,k

poj3471 - 倍增+LCA+树上差分

题意:一张n节点连通无向图,n-1条树边,m条非树边.若通过先删一条树边,再删一条非树边想操作 将此图划分为不连通的两部分,问有多少种方案. 利用LCA整好区间覆盖,dfs用来求前缀和 需要注意的是,覆盖数为1的时候才可以选择哦! 覆盖数为0,代表可以直接拆开 最后附上一张我老婆 #include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #define maxn 110

差分 and 树上差分

差分数组 定义 百度百科中的差分定义 //其实这完全和要讲的没关系 qwq 进去看了之后是不是觉得看不懂? 那我简单概括一下qwq 差分数组de定义:记录当前位置的数与上一位置的数的差值. 栗子 容易发现的是,\(\sum_{1}^{i}{b_i}\)即代表\(a_i\) 的值. \((\sum_{1}^{i}\) 即代表从1累加到i.) 思想 看到前面的\(\sum_{1}^{i}\) 你一定会发现这是前缀和! 那你认为这是前缀和? 的确是qwq. 实际上这并不是真正意义上的前缀和. 前缀和的

差分数组 and 树上差分

差分数组 定义 百度百科中的差分定义 //其实这完全和要讲的没关系 qwq 进去看了之后是不是觉得看不懂? 那我简单概括一下qwq 差分数组de定义:记录当前位置的数与上一位置的数的差值. 栗子 容易发现的是,\(\sum_{j=1}^{i} b_j\)即代表\(a_i\) 的值. \((\sum\) 即代表累加.) 思想 看到前面的\(\sum\) 你一定会发现这是前缀和! 那你认为这是前缀和? 的确是qwq. 实际上这并不是真正意义上的前缀和. 前缀和的思想是 根据元素与元素之间的并集关系(

[填坑]树上差分 例题:[JLOI2014]松鼠的新家(LCA)

今天算是把LCA这个坑填上了一点点,又复习(其实是预习)了一下树上差分.其实普通的差分我还是会的,树上的嘛,也是懂原理的就是没怎么打过. 我们先来把树上差分能做到的看一下: 1.找所有路径公共覆盖的边 例题:[NOIP2015]运输计划 (然而我还没过就先不讲了) 反正就是中间有一步要求一条边被所有计划公共覆盖. 那么怎么求它呢?暴力(滚粗).我们有一个非常好的方法就是树上差分(记录tmp为差分数组) 询问操作为从叶子节点的权值向上累加到root 在一条路径u→ v,如果tmp[u]++,那么我