poj 3417 Network

Description:

  先给出一棵无根树,然后下面再给出m条边,把这m条边连上,然后每次你能毁掉两条边,规定一条是树边,一条是新边,问有多少种方案能使树断裂。

思路:

  当你在树上连边的时候,树就会形成一个环,然后把在环内切边,那么第二刀任意。如果一条边在两个环内,第二刀唯一,如果在两个以上环内,无解。

 也就是每次连边之后,求每条边的覆盖次数。应用树上差分(乱搞)算法可得解

#include<iostream>
#include<vector>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 1e5 + 10, M = 2e5 + 10;
typedef pair<int,int> P;

int head[N], now;
struct edges{
    int to, next;
}edge[N<<1];
void add(int u,int v){ edge[++now] = {v, head[u]}; head[u] = now;}

int n, m, lca[N], fa[N], vis[N], w[N];
vector<P> q[N];

int get(int x){
    if(x != fa[x]) return fa[x] = get(fa[x]);
    return x;
}
void tarjan(int x){
    vis[x] = 1;
    for(int i = head[x]; i; i = edge[i].next){
        int v = edge[i].to;
        if(vis[v]) continue;
        tarjan(v);
        fa[v] = x;
    }
    for(int i = 0; i < q[x].size(); i++){
        int v = q[x][i].first, id = q[x][i].second;
        if(vis[v] == 2)
          lca[id] = get(v);
    }
    vis[x] = 2;
}
int ans[N];
void dfs(int x){
    ans[x] = w[x], vis[x] = 1;
    for(int i = head[x]; i; i = edge[i].next){
        int v = edge[i].to;
        if(vis[v]) continue;
        dfs(v);
        ans[x] += ans[v];
    }
}
void init(){
    memset(w,0,sizeof(w));
    memset(edge,0,sizeof(edge)); now = 0;
    memset(head,0,sizeof(head));
    memset(ans,0,sizeof(ans));
    memset(vis,0,sizeof(vis));
    memset(lca,0,sizeof(lca));
}
int main(){
//    freopen("wrong.in","r",stdin);
    while(scanf("%d%d", &n, &m) != EOF){
        init();
        int x, y;
        for(int i = 1; i <= n; i++) fa[i] = i;
        for(int i = 1; i < n; i++){
            scanf("%d%d",&x, &y);
            add(x, y); add(y, x);
        }
        for(int i = 1; i <= m; i++){
            scanf("%d%d",&x, &y);
            q[x].push_back(P(y, i));
            q[y].push_back(P(x, i));
            w[x]++, w[y]++;
            if(x == y) lca[i] = x;
        }
        tarjan(1);
        for(int i = 1; i <= m; i++)
          w[lca[i]] -= 2;
        memset(vis,0,sizeof(vis));
        dfs(1);
        int tot = 0;
        for(int i = 2; i <= n; i++){
            if(ans[i] == 0) tot += m;
            if(ans[i] == 1) tot++;
        }
        printf("%d\n",tot);
        for(int i = 1; i <= n; i++)
          q[i].clear();
    }    
    return 0;
}

 

posted @ 2018-04-05 22:00  Ror_shach  阅读(168)  评论(0编辑  收藏  举报