http://poj.org/problem?id=3417

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

我们考虑加上每一条新边的情况,当一条新边加上之后,原本的树就会成环,环上除了所有的树边要断的话必然要砍掉这条新边才可行。

每一条新边成的环就是u - lca(u,v) - v,对每一条边的覆盖次数++

考虑所有的树边,被覆盖 == 0的时候,意味着单独砍掉这条树边即可,其他随便选一个新边就是一种方案,贡献值 += M;

被覆盖 == 1的时候,意味着砍掉这条树边必须砍掉另一条与他匹配的新边,贡献值 ++

被覆盖 >= 2的时候,这条树边被砍掉是没有意义的,因为不可能同时砍掉两条以上的新边

下面的问题就变成了如何求每一条边的被覆盖次数,我们只要对dp[lca] -= 2,dp[u]++,dp[v]++从根节点向下推,到叶子节点之后回溯,更新dp值即可

这就变成了一个喜闻乐见的树dp、

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
const double eps = 1e-;
const int maxn = 1e5 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,tmp,K;
int head[maxn],tot,cnt;
bool vis[maxn];
int F[maxn * ],P[maxn],rmq[maxn * ];
struct Edge{
int to,next;
}edge[maxn * ];
int dp[maxn];
LL sum;
struct ST{
int dp[maxn * ][];
int mm[maxn * ];
void init(int n){
mm[] = -;
for(int i = ; i <= n ; i ++){
mm[i] = ((i & (i - )) == )?mm[i - ] + :mm[i - ];
dp[i][] = i;
}
for(int j = ; j <= mm[n]; j ++){
for(int i = ; i + ( << j) - <= n ; i ++){
dp[i][j] = rmq[dp[i][j - ]] < rmq[dp[i + ( << (j - ))][j - ]]?dp[i][j - ]:dp[i + ( << (j - ))][j - ];
}
}
}
int query(int a,int b){
if(a > b) swap(a,b);
int k = mm[b - a + ];
return rmq[dp[a][k]] <= rmq[dp[b - ( << k) + ][k]]?dp[a][k]:dp[b - ( << k) + ][k];
}
}st;
void init(){
Mem(head,-);
tot = ;
}
void add(int u,int v){
edge[tot].next = head[u];
edge[tot].to = v;
head[u] = tot++;
}
void dfs(int u,int pre,int dep){
F[++cnt] = u;
rmq[cnt] = dep;
P[u] = cnt;
for(int i = head[u]; ~i; i = edge[i].next){
int v = edge[i].to;
if(v == pre ) continue;
dfs(v,u,dep + );
F[++cnt] = u;
rmq[cnt] = dep;
}
}
void LCA_init(int root){
cnt = ;
dfs(root,root,);
st.init( * N - );
}
int lca(int u,int v){
return F[st.query(P[u],P[v])];
}
int dfs2(int x,int last){
for(int i = head[x]; ~i ; i = edge[i].next){
int to = edge[i].to;
if(to == last) continue;
dfs2(to,x);
dp[x] += dp[to];
if(dp[to] == ) sum++;
else if(!dp[to]) sum += M;
}
return dp[x];
}
int main()
{
Sca2(N,M);
init();
For(i,,N - ){
int u,v; Sca2(u,v);
add(u,v); add(v,u);
}
LCA_init();
For(i,,M){
int u,v; Sca2(u,v);
dp[u]++; dp[v]++; dp[lca(u,v)] -= ;
}
dfs2(,-);
Prl(sum);
#ifdef VSCode
system("pause");
#endif
return ;
}

POJ3417 LCA+树dp的更多相关文章

  1. poj3417 LCA + 树形dp

    Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4478   Accepted: 1292 Descripti ...

  2. poj3417 Network 树形Dp+LCA

    题意:给定一棵n个节点的树,然后在给定m条边,去掉m条边中的一条和原树中的一条边,使得树至少分为两部分,问有多少种方案. 神题,一点也想不到做法, 首先要分析出加入一条边之后会形成环,形成环的话,如果 ...

  3. bzoj 3572世界树 虚树+dp

    题目大意: 给一棵树,每次给出一些关键点,对于树上每个点,被离它最近的关键点(距离相同被标号最小的)控制 求每个关键点控制多少个点 分析: 虚树+dp dp过程如下: 第一次dp,递归求出每个点子树中 ...

  4. bzoj 2286 [Sdoi2011]消耗战 虚树+dp

    题目大意:多次给出关键点,求切断边使所有关键点与1断开的最小费用 分析:每次造出虚树,dp[i]表示将i和i子树与父亲断开费用 对于父亲x,儿子y ①y为关键点:\(dp[x]\)+=\(dismn( ...

  5. 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP

    [题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...

  6. [BZOJ2286][SDOI2011]消耗战(虚树DP)

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4998  Solved: 1867[Submit][Statu ...

  7. [BZOJ2125]最短路(圆方树DP)

    题意:仙人掌图最短路. 算法:圆方树DP,$O(n\log n+Q\log n)$ 首先建出仙人掌圆方树(与点双圆方树的区别在于直接连割边,也就是存在圆圆边),然后考虑点u-v的最短路径,显然就是:在 ...

  8. BZOJ 3572 [HNOI2014]世界树 (虚树+DP)

    题面:BZOJ传送门 洛谷传送门 题目大意:略 细节贼多的虚树$DP$ 先考虑只有一次询问的情况 一个节点$x$可能被它子树内的一个到x距离最小的特殊点管辖,还可能被管辖fa[x]的特殊点管辖 跑两次 ...

  9. 洛谷P2495 [SDOI2011]消耗战(虚树dp)

    P2495 [SDOI2011]消耗战 题目链接 题解: 虚树\(dp\)入门题吧.虚树的核心思想其实就是每次只保留关键点,因为关键点的dfs序的相对大小顺序和原来的树中结点dfs序的相对大小顺序都是 ...

随机推荐

  1. JAVA js WEB 疑难点总结

    1.获取combox的Value 和 Text    $('#id').combobox('getValue').$('#id').combobox('getText'): 2.ajax 直接访问ht ...

  2. CABAC总结与补充讨论

    在之前的一篇文章CABAC中我们已经对算法中的大部分细节部分做了详细分析,这里做一个总结与拾遗. 总结 CABAC的编码可以分为以下四个部分: 上下文变量的初始化 待编码语法元素二值化 上下文建模(确 ...

  3. Python介绍及环境配置

    Python 简介 Python 是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言. Python 的设计具有很强的可读性,相比其他语言经常使用英文关键字,其他语言的一些标点符号,它具有 ...

  4. Linux下的好用的编辑软件Remarkable

    Linux下的好用的编辑软件Remarkable最近着手开始学习Linux,就想着找一款好用的编辑器作笔记,在网上爬了些贴选择了Remarkable.官网崩了,有没有梯子,废了好大力气才装好.于是把资 ...

  5. Sublime Text3 如何开启Debug

    打开setting-user 首选项——>Package Settings——>Package Control——>settings-user 添加"debug" ...

  6. 数据结构与算法(Python)

    一.数据结构与算法概述 数据结构与算法的定义 我们把现实中大量而且非常复杂的问题以特定的数据类型(个体)和特定的存储结构(个体的关系)保存到相应的主存储器(内存)中,以及在此基础上为实现某个功能而执行 ...

  7. 查询SQL执行情况

    /* 查询SQL执行情况 包含逻辑读取信息,执行信息等情况*/ SELECT creation_time N'语句编译时间' ,last_execution_time N'上次执行时间' ,total ...

  8. MobaXterm之取消自动关闭连接 Network error :Connection timed out

    连一会就出现连接重来的问题 配置如下.

  9. 【cf849ABC】

    849A - Odds and Ends 问能否将序列划分为奇数个长度奇数的奇数开头奇数结尾的子区间. 一开始想dp..不过没必要. const int N=201000; int n,a[N]; i ...

  10. 【Luogu3602】Koishi Loves Segments(贪心)

    [Luogu3602]Koishi Loves Segments(贪心) 题面 洛谷 题解 离散区间之后把所有的线段挂在左端点上,从左往右扫一遍. 对于当前点的限制如果不满足显然会删掉右端点最靠右的那 ...