codeforce 891 D

题链

SOL:我们易得 N&1 时答案为0.

我们再考虑偶数。我们知道树的完美匹配<=1.(证明方法是贪心的把叶子拿下来)。

如果存在完美匹配的话,我们知道要用到的匹配边两侧有奇数个点,

不用到的边两侧有偶数个点,

我们知道输入不一定是有完美匹配的。那么我们可以用边旁边的点得奇偶性来分类这样的边,然后我们知道,有偶数个边的只要合法,就可以任意连,奇数的一定要连奇路径。(就是奇偶奇偶边交替出现始末都是奇的路径)。

bb了这么多,还是选择抄杜爷的代码。

#include<bits/stdc++.h>
#define sight(c) ('0'<=c&&c<='9')
#define VI vector<int>
#define PII pair<int,int>
#define mp make_pair
#define mo 1000000007
#define pb push_back
#define it iterator
#define fi first
#define se second
#define N 501007
#define SI(a) ((int)a.size())
#define LL long long
#define As assert 
#define deg printf
#define dput put
#define dwl writel
#define dwln writeln
#define dputc putchar
#define db double 
#define eho(x) for(int i=head[x];i;i=net[i])
using namespace std;
inline char nc(){
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
    static char c;
    for (c=getchar();!sight(c);c=getchar());
    for (x=0;sight(c);c=getchar())x=x*10+c-48;
}
void write(LL x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);}
inline void writeln(LL x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('\n'); }
inline void writel(LL x){ if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); }
int n,pa[N],ev[N],si[N],ret[N];
PII dp[N],pd[N],fp[N],fs[N];
LL ans;int fall[N<<1],net[N<<1],head[N],tot;
inline void add(int x,int y){fall[++tot]=y; net[tot]=head[x]; head[x]=tot;}
PII gao (PII A,PII B){
    if (A.fi>B.fi) return A;
    if (A.fi<B.fi) return B;
    return mp(A.fi,A.se+B.se);
}
#define SON fall[i]
void dfs(int x,int fa){
    pa[x]=1; si[x]=1; ev[x]=0; dp[x]=mp(0,1);
    eho(x) if (SON^fa){
        dfs(SON,x); pa[x]^=pa[SON];
        si[x]+=si[SON]; ev[x]+=ev[SON];
        pa[SON]?dp[x]=gao(dp[x],mp(dp[SON].fi+1,dp[SON].se)):(ev[x]++,dp[x]=gao(dp[x],mp(dp[SON].fi-1,dp[SON].se)));
    }
    if (pa[x]==1) {
        As(ev[x]+dp[x].fi<=si[x]/2);
        if (ev[x]+dp[x].fi!=si[x]/2) ret[x]=0;
        else ret[x]=dp[x].se;// 判是否合法 
    }
}
void dfs2(int x,int fa){
    VI s; s.pb(x);
    eho(x) if (SON^fa) s.pb(SON);
    int m=SI(s);
    fp[0]=gao(pd[x],mp(0,1));
    for (int i=1;i<m;i++) {
        int v=s[i];
        if (!pa[v]) fp[i]=gao(fp[i-1],mp(dp[v].fi-1,dp[v].se));
        else fp[i]=gao(fp[i-1],mp(dp[v].fi+1,dp[v].se));
    }
    fs[m]=mp(-(1<<30),0);
    for (int i=m-1;i;i--) {
        int v=s[i];
        if (pa[v]==0) fs[i]=gao(fs[i+1],mp(dp[v].fi-1,dp[v].se));
        else fs[i]=gao(fs[i+1],mp(dp[v].fi+1,dp[v].se));
    }
    for (int i=1;i<m;i++) {
        int v=s[i];
        pd[v]=gao(fp[i-1],fs[i+1]);
        if (pa[v]==1) {
            assert(ev[1]-ev[v]+pd[v].fi<=(n-si[v])/2);
            if (ev[1]-ev[v]+pd[v].fi==(n-si[v])/2) {
                ans+=(LL)pd[v].se*ret[v];
            }
        }
        if (pa[v]==0) pd[v].fi--; else pd[v].fi++;
    }
    eho(x) if (SON^fa) dfs2(SON,x);
}
int u,v;
signed main() {
//    freopen("a.in","r",stdin);
    read(n);
    if (n&1) return puts("0"),0;
    for (int i=n-1;i;i--)
     read(v),read(u),add(u,v),add(v,u);
    dfs(1,0);
//    for(int i=1;i<=n;i++) dwl(dp[i].fi); dputc('\n');
    if (ev[1]==n/2-1) 
      for (int i=2;i<=n;i++) pa[i]?:ans+=(LL)si[i]*(n-si[i]);
    dfs2(1,0); 
    writeln(ans);
    return 0;
}

 

转载于:https://www.cnblogs.com/rrsb/p/8349976.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值