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
之后统计贡献就可以做了
代码:
给定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; }
相关文章推荐
- 基于Android中dp和px之间进行转换的实现代码
- Android中dip、dp、sp、pt和px的区别详解
- LFC1.0.0 版本发布
- Android px、dp、sp之间相互转换
- HP data protector软件学习1--基本角色与基本工作流程
- HP data protector软件学习2--软件组成与界面介绍
- android中像素单位dp、px、pt、sp的比较
- Android对px和dip进行尺寸转换的方法
- Android根据分辨率进行单位转换-(dp,sp转像素px)
- android 尺寸 dp,sp,px,dip,pt详解
- DP问题各种模型的状态转移方程
- LCA模板
- POJ-1695-Magazine Delivery-dp
- nyoj-1216-整理图书-dp
- TYVJ1193 括号序列解题报告
- 对DP的一点感想
- TYVJ上一些DP的解题报告
- soj1005. Roll Playing Games
- 01背包问题
- LeetCode之Maximum Product Subarray