《牛客IOI周赛17提高组A》

题意:对于题意可以分解为.

有n个点,由n-1条白色的边连接,同时又有着m条边.

因为这里说到了白色的边都不重复也不缠绕,显然是n-1条边构成树边.

然后有m条非树边。然后问我们删去一条树边和一条非树边使树分为两部分。这条边完全断开.

思路:

我们可以从每条树边出发。

对于每条树边。

如果没有非树边覆盖到它.那么删去所有中任意的非树边都可以.即m种方案.
如果有一条非树边覆盖到它,那么只有删去这条树边才可以.即1种方案.
如果有两条及以上的非树边覆盖到它,那么删去非树边中的任意一条都不行,依旧会连通.所以此时方案为0.
 
统计树边的覆盖情况采用树上差分的边差分.
 
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 2e5+5;
const int M = 1e6+5;
const int Mod = 1e9+7;
#define pi acos(-1)
#define INF 1e8
#define INM INT_MIN
#define pb(a)  push_back(a)
#define mk(a,b) make_pair(a,b)
#define dbg(x) cout << "now this num is " << x << endl;
#define met0(axx) memset(axx,0,sizeof(axx));
#define metf(axx) memset(axx,-1,sizeof(axx));
#define sd(ax) scanf("%d",&ax)
#define sld(ax) scanf("%lld",&ax)
#define sldd(ax,bx) scanf("%lld %lld",&ax,&bx)
#define sdd(ax,bx) scanf("%d %d",&ax,&bx)
#define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx)
#define sfd(ax) scanf("%lf",&ax)
#define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx)
#define pr(a) printf("%d\n",a)
#define plr(a) printf("%lld\n",a)
/*
对于一条树边.
如果没有非树边覆盖到它.那么所有的非树边都可以.即m.
如果有一条非树边覆盖到它,那么删去这条树边.即1.
如果有两条及以上的非树边覆盖到它,那么删去非树边中的任意一条都不行,依旧会连通.所以此时方案为0
*/
vector<int> G[N];
int n,m,dep[N],f[N][25],lg[25],c[N];//i到父节点的边被多少条非树边覆盖
LL ans = 0;
void init()
{
    lg[0] = 1;for(int i=1;i<25;++i) lg[i] = lg[i-1]<<1;
}
void dfs(int u,int fa)
{
    dep[u] = dep[fa]+1;
    f[u][0] = fa;
    for(int i=1;i<25;++i) f[u][i] = f[f[u][i-1]][i-1];
    for(auto v:G[u]) if(v != fa) dfs(v,u);
}
int Lca(int x,int y)
{
    if(dep[x] < dep[y]) swap(x,y);
    int dix = dep[x]-dep[y];
    for(int i=24;i>=0;--i)
    {
        if(lg[i] <= dix) dix -= lg[i],x = f[x][i];
    }
    if(x == y) return x;
    for(int i=24;i>=0;--i)
    {
        if(lg[i] <= dep[x] && f[x][i] != f[y][i]) x = f[x][i],y = f[y][i];
    }
    return f[x][0];
}
void dfs1(int u,int fa)
{
    for(auto v:G[u])
    {
        if(v == fa) continue;
        dfs1(v,u);
        c[u] += c[v];
        if(c[v] == 0) ans += m;
        else if(c[v] == 1) ans++;
        //else都不能.
    }
}
void slove()
{
    init();
    sdd(n,m);
    for(int i=1;i<n;++i)
    {
        int u,v;sdd(u,v);
        G[u].pb(v),G[v].pb(u);
    }
    dfs(1,0);
    for(int i=1;i<=m;++i)
    {
        int u,v;sdd(u,v);
        c[u]++,c[v]++,c[Lca(u,v)]-=2;
    }
    dfs1(1,0);
    plr(ans);
}  
int main()
{
    slove();
    system("pause");
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zwjzwj/p/13061911.html