poj3417暗的连锁

试题描述
Dark 是一张无向图,图中有 N 个节点和两类边,一类边被称为主要边,而另一类被称为附加边。Dark 有 
N–1 条主要边,并且 Dark 的任意两个节点之间都存在一条只由主要边构成的路径。另外,Dark 还有 M 条附加边。
你的任务是把 Dark 斩为不连通的两部分。一开始 Dark 的附加边都处于无敌状态,你只能选择一条主要边切断。一旦你切断了一条主要边,Dark 就会进入防御模式,主要边会变为无敌的,而附加边可以被切断。但是你的能力只能再切断 Dark 的一条附加边。现在你想要知道,一共有多少种方案可以击败 Dark。注意,就算你第一步切断主要边之后就已经把 Dark 斩为两截,你也需要切断一条附加边才算击败了 Dark。
输入
第一行包含两个整数 N 和 M。
之后 N–1 行,每行包括两个整数 A 和 B,表示 A 和 B 之间有一条主要边;
之后 M 行以同样的格式给出附加边。
输出
输出一个整数表示结果。
输入示例
4 1 
1 2 
2 3 
1 4 
3 4
输出示例
3
其他说明
数据规模
对于 20% 的数据,N≤100,M≤100。
对于 100% 的数据,N≤10^5,M≤2×10^5。数据保证答案不超过 2^31−1。

我们要讲这道题的模型抽象出来,首先主要便形成一颗树

然后每次加进去一条非树边就会多一个环,也就是在这个环上的每一条主要边所联通的两个点之间就会多一条路径

相当于是换上的每条主要边被覆盖一次,也就是加一

现在这道题就被抽象成了一个树上差分

下面给出代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
inline int rd(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
inline void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
    return ;
}
int n,m;
int head[100006],nxt[100006],to[100006];
int total=0;
int d[100006];
int vis[100006];
void add(int x,int y){
    total++;
    to[total]=y;
    nxt[total]=head[x];
    head[x]=total;
    return ;
}
int f[100006][21];
void dfs(int x,int fa){
    f[x][0]=fa;
    for(int e=head[x];e;e=nxt[e]){
        d[to[e]]=d[x]+1;
        dfs(to[e],x);
    }
    return ;
}
void pre(){for(int j=1;j<=20;j++) for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1];}
int LCA(int x,int y){
    if(d[x]<d[y]) swap(x,y);
    for(int i=20;i>=0;i--) if(d[f[x][i]]>=d[y]) x=f[x][i];
    if(x==y) return x;
    for(int i=20;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
int ans=0;
void solve(int x,int fa){
    for(int e=head[x];e;e=nxt[e]){
        solve(to[e],x);
        vis[x]+=vis[to[e]];
    }
    if(x==1) return ;
    if(vis[x]==1) ans+=1;
    if(!vis[x]) ans+=m;
    return ;
}
int main(){
    n=rd(),m=rd();
    for(int i=1;i<n;i++){
        int x=rd(),y=rd();
        add(x,y);
    }
    d[1]=1;
    dfs(1,0);
    pre();
    for(int i=1;i<=m;i++){
        int x=rd(),y=rd();
        vis[x]++,vis[y]++,vis[LCA(x,y)]-=2;
    }
    solve(1,0);
    printf("%d",ans);
    return 0;
}

 

posted @ 2018-10-17 20:20  Bruce--Wang  阅读(418)  评论(0编辑  收藏  举报