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. Tyche 2317 Color

    题目大意:有三个人alice,bob,yazid,三种颜色red,blue,green,每个人对应一种颜色. [name] is [color]. Yazid会做以下操作: 1 将三个句子连在一起 2 ...

  3. python基础数据类型--dict 字典

    字典 字典是python中唯一的映射类型,采用键值对(key-value)的形式存储数据.python对key进行哈希函数运算,根据计算的结果决定value的存储地址,所以字典是无序存储的,且key必 ...

  4. [NOIP]2017列队——旋转treap/非旋转treap

    Sylvia 是一个热爱学习的女孩子.  前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia所在的方阵中有n × m名学生,方阵的行数为 n,列数为m.  为了便 ...

  5. Django ContentType组件

    ContentType组件 引入 现在我们有这样一个需求~我们的商城里有很多的商品~~节日要来了~我们要搞活动~~ 那么我们就要设计优惠券~~优惠券都有什么类型呢~~满减的~折扣的~立减的~~ 我们对 ...

  6. CH2906 武士风度的牛(算竞进阶习题)

    水..... 直接bfs... #include <bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; typedef l ...

  7. [USACO07JAN]Cow School

    题目链接:[USACO07JAN]Cow School 一开始还以为是一道分数规划,后来发现自己看错题了, 然后成功入坑 题目是要求先按照$t_i/p_i$从小到大排序,然后删除前$d$个后求出剩下的 ...

  8. 【HDU5950】Recursive sequence(矩阵快速幂)

    BUPT2017 wintertraining(15) #6F 题意 \(f(1)=a,f(2)=b,f(i)=2*(f(i-2)+f(i-1)+i^4)\) 给定n,a,b ,\(N,a,b < ...

  9. 【hjmmm网络流24题补全计划】

    本文食用方式 按ABC--分层叙述思路 可以看完一步有思路后自行思考 飞行员配对问题 题目链接 这可能是24题里最水的一道吧... 很显然分成两个集合 左外籍飞行员 右皇家飞行员 跑二分图最大匹配 输 ...

  10. 登录Linux服务器显示IP和自定义备注

    默认搭建好的Linux服务器,使用Xshell登录的窗口如下所示: 可根据需要执行如上代码,再重新登录服务器,效果如下图所示: 代码片段:echo "export PS1='\u@\[\e[ ...