您的位置:首页 > 其它

POJ 3417 Network(dp+LCA)

2016-01-27 23:23 483 查看
题意:

给定N≤105的一棵树,新添加M≤105条边

现在每次可以毁掉2条边,一条必须是树边,一条是新边,问有多少种方法使得树不连通

分析:

我们知道加入新边必定会成环,可以发现

对于被环覆盖2次及以上的树边,贡献是0

对于被环覆盖1次的树边,贡献是1

对于被环覆盖0次的树边,贡献是M

然后用树形dp,dp[u]:=(u,f)这条边被环覆盖的次数

对于(u,v),先计数dp[u]++,dp[v]++,自底向上dp之后就可以把环上的点都更新了,但是对于环上的点来说显然lca要减去,dp[lca]−=2

之后统计贡献就可以做了

代码:

//
//  Created by TaoSama on 2015-11-11
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, m, dp
;

struct Edge {
int v, nxt;
} E[N << 1];
int headE
, cnt;

void addEdge(int u, int v) {
E[cnt] = (Edge) {v, headE[u]};
headE[u] = cnt++;
E[cnt] = (Edge) {u, headE[v]};
headE[v] = cnt++;
}

struct Query {
int v, nxt, id;
} Q[N << 1];
int headQ
;

void addQuery(int u, int v, int id) {
Q[cnt] = (Query) {v, headQ[u], id};
headQ[u] = cnt++;
Q[cnt] = (Query) {u, headQ[v], id};
headQ[v] = cnt++;
}

bool vis
, checked
;
int ancestor
;

int find(int x) {
return ancestor[x] = ancestor[x] == x ? x : find(ancestor[x]);
}

void tarjan(int u) {
ancestor[u] = u;
vis[u] = true;
for(int i = headE[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if(vis[v]) continue;
tarjan(v);
ancestor[v] = u;
}
for(int i = headQ[u]; ~i; i = Q[i].nxt) {
int v = Q[i].v, id = Q[i].id;
if(!vis[v]) continue;
if(checked[id]) continue;
checked[id] = true;
int lca = find(v);
dp[lca] -= 2;
}
}

void dfs(int u, int f) {
for(int i = headE[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if(v == f) continue;
dfs(v, u);
dp[u] += dp[v];
}
}

int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);

while(scanf("%d%d", &n, &m) == 2) {
cnt = 0; memset(headE, -1, sizeof headE);
for(int i = 1; i < n; ++i) {
int u, v; scanf("%d%d", &u, &v);
addEdge(u, v);
}
cnt = 0; memset(headQ, -1, sizeof headQ);
memset(dp, 0, sizeof dp);
for(int i = 1; i <= m; ++i) {
int u, v; scanf("%d%d", &u, &v);
addQuery(u, v, i);
++dp[u]; ++dp[v];
}

memset(vis, false, sizeof vis);
memset(checked, false, sizeof checked);
tarjan(1);

dfs(1, -1);

int ans = 0;
for(int i = 2; i <= n; ++i) {
if(dp[i] == 0) ans += m;
else if(dp[i] == 1) ++ans;
}
printf("%d\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp LCA