[poj3417]Network(LCA+树形dp)

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

解题关键:边权转化为点权,记录每条边被环覆盖的次数,通过val[a]++,val[b]++,val[lca(a,b)]-=2,来控制每个点上面的边,所以树的顶点要去掉。

好久没1A了,开心

  1 //#pragma comment(linker, "/STACK:1024000000,1024000000")
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cstdlib>
  6 #include<cmath>
  7 #include<iostream>
  8 #include<vector>
  9 typedef long long ll;
 10 using namespace std;
 11 const int maxn=101000;
 12 const int maxm=30;
 13 int _pow[maxm],m,n;
 14 int head[maxn],tot;
 15 int ver[maxn*2],depth[maxn*2],first[maxn],rmq[maxn*2][25],id;//5个数组,注意哪个需要乘2
 16 int pre[maxn],val[maxn];
 17 int ans;
 18 inline int read(){
 19     char k=0;char ls;ls=getchar();for(;ls<‘0‘||ls>‘9‘;k=ls,ls=getchar());
 20     int x=0;for(;ls>=‘0‘&&ls<=‘9‘;ls=getchar())x=(x<<3)+(x<<1)+ls-‘0‘;
 21     if(k==‘-‘)x=0-x;return x;
 22 }
 23
 24 struct edge{
 25     int to,nxt;
 26 }e[maxn*2];//链式前向星建树
 27
 28 void init(){
 29     memset(head,-1,sizeof head);
 30     tot=0;
 31     id=0;
 32     ans=0;
 33 }
 34
 35 void add_edge(int u,int v){
 36     e[tot].to=v;
 37     e[tot].nxt=head[u];
 38     head[u]=tot++;
 39 }
 40
 41 void dfs(int u,int fa,int dep){
 42     ver[++id]=u;//第i个访问到的结点编号
 43     depth[id]=dep;//第i个访问到的结点深度
 44     first[u]=id;
 45     for(int i=head[u];i!=-1;i=e[i].nxt){
 46         int v=e[i].to;
 47         if(v==fa) continue;
 48         //pre[v]=u;
 49         dfs(v,u,dep+1);
 50         ver[++id]=u;//后序遍历,再次访问父节点
 51         depth[id]=dep;
 52     }
 53 }
 54
 55 void rmq_init(int n){
 56     int k=int(log(n)/log(2));
 57     for(int i=1;i<=n;++i)    rmq[i][0]=i;
 58     for(int j=1;j<=k;++j){
 59         for(int i=1;i+_pow[j]-1<=n;++i){//因为存的是索引
 60             int a=rmq[i][j-1],b=rmq[i+_pow[j-1]][j-1];
 61             rmq[i][j]=depth[a]<depth[b]?a:b;
 62         }
 63     }
 64 }
 65
 66 int rmq_query(int l,int r){
 67     int k=int(log(r-l+1.0)/log(2.0));
 68     int a=rmq[l][k],b=rmq[r-_pow[k]+1][k];
 69     return depth[a]<depth[b]?a:b;
 70 }//返回的依然是索引
 71
 72 int LCA(int u,int v){
 73     int x=first[u],y=first[v];
 74     if(x>y)swap(x,y);
 75     int res=rmq_query(x,y);
 76     return ver[res];
 77 }
 78 void dfs(int u,int fa){
 79     for(int i=head[u];i!=-1;i=e[i].nxt){
 80         int v=e[i].to;
 81         if(v==fa) continue;
 82         dfs(v,u);
 83         val[u]+=val[v];
 84     }
 85     if(val[u]==1) ans++;
 86     else if(!val[u]&&u!=1) ans+=m;
 87 }
 88
 89 int main(){
 90     for(int i=0;i<maxm;++i)    _pow[i]=1<<i; //预处理2^n
 91     int k,a,b;
 92     n=read();m=read();
 93     init();
 94     //for(int i=1;i<=n;i++) val[i]=read();
 95     for(int i=0;i<n-1;++i){
 96         a=read(),b=read();
 97         add_edge(a,b);
 98         add_edge(b,a);
 99     }
100     dfs(1,-1,0);
101     rmq_init(2*n-1);
102     for(int i=0;i<m;++i){
103         a=read();b=read();
104         val[a]++,val[b]++,val[LCA(a,b)]-=2;
105     }
106     dfs(1,-1);
107     printf("%d\n",ans);
108
109     return 0;
110 }
时间: 2024-08-07 07:47:33

[poj3417]Network(LCA+树形dp)的相关文章

HDU 4008 Parent and son LCA+树形dp

题意: 给定case数 给定n个点的树,m个询问 下面n-1行给出树边 m个询问 x y 问:以x为根,y子树下 y的最小点标的儿子节点 和子孙节点 思路: 用son[u][0] 表示u的最小儿子 son[u][2] 表示u的次小儿子 son[u][1] 表示u的最小子孙 若lca(x,y)  !=y  则就是上述的答案 若lca(x,y) == y 1.y != 1 那么最小儿子就是除了x外的节点,且此时father[y] 也是y的儿子节点, 而最小的子孙节点就是1 2.y==1 那么特殊处理

poj3417 LCA + 树形dp

Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4478   Accepted: 1292 Description Yixght is a manager of the company called SzqNetwork(SN). Now she's very worried because she has just received a bad news which denotes that DxtNet

codeforces 500D - New Year Santa Network (树形DP+组合数学)

题目地址:http://codeforces.com/contest/500/problem/D 这题是要先求出每条边出现的次数,然后除以总次数,这样期望就求出来了.先用树形DP求出每个边左右两端总共有多少个点,然后用组合数学公式就可以推出来了. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm>

POJ - 3417 Network(LCA + DP)

题目大意:给出一棵N个结点的无根树,现在要在上面加上M条边,问,有多少种破坏方式(破坏一条树边,一条新边),能使这张新图变成至少两部分 解题思路:首先,假设添加的边为(u,v),那么u – > lca(u,v) –> v – >u就形成了一个环了,也就是说,每条添加的边都会在树上形成一个环 本来树上的每条边都是一条桥的,由于加了新的边了,形成了连通分量了,使得边的性质发生了些变化 首先,树边在0个连通分量里面的,那表示该树边还是桥,破坏了它,图肯定能分成两个部分,所以破坏方式就有M种了

HDOJ 5293 Tree chain problem LCA+树链剖分+树形DP

[题意] 给定一颗树上的几条链和每条链的权值,求能取出的不含有公共节点的链的最大权值.... [解] 预处理每条链的lca 树形DP, d[i]表示取到这个节点时可以得到的最大值 , sum[i]=sigma( d[k] | k 是i的子节点) 如果不取i  d[i]=sum[i] 如果取i , e是lca为i的链则 d[i]=max(d[i],e的权值+sigma(sum[k])-sigma(d[k]))  k为树链上的点 可以用树链剖分+树装数组在nlogn的时间复杂度内求链上的值 Tree

Codeforces 418d Big Problems for Organizers [树形dp][倍增lca]

题意: 给你一棵有n个节点的树,树的边权都是1. 有m次询问,每次询问输出树上所有节点离其较近结点距离的最大值. 思路: 1.首先是按照常规树形dp的思路维护一个子树节点中距离该点的最大值son_dis[i],维护非子树节点中距离该点的最大值fa_dis[i]; 2.对于每个节点维护它最大的三个儿子节点的son_dis; 3.维护up[i][j]和down[i][j]数组,这个类似倍增lca里边的fa[i][j],up[i][j]代表的含义是从第j个点向上到它的第2^i个父节点这条链上的点除了该

SGU 149. Computer Network( 树形dp )

题目大意:给N个点,求每个点的与其他点距离最大值 很经典的树形dp...很久前就想写来着...看了陈老师的code才会的...mx[x][0], mx[x][1]分别表示x点子树里最长的2个距离, dfs一遍得到. mx[x][2]表示从x的父亲到x的最长路径长度, 也是dfs一遍得到(具体看代码).最后答案就是max(mx[x][0], mx[x][2]). 时间复杂度O(N) ----------------------------------------------------------

【bzoj3362/3363/3364/3365】[Usaco2004 Feb]树上问题杂烩 并查集/树形dp/LCA/树的点分治

题目描述 农夫约翰有N(2≤N≤40000)个农场,标号1到N,M(2≤M≤40000)条的不同的垂直或水平的道路连结着农场,道路的长度不超过1000.这些农场的分布就像下面的地图一样, 图中农场用F1..F7表示, 每个农场最多能在东西南北四个方向连结4个不同的农场.此外,农场只处在道路的两端.道路不会交叉且每对农场间有且仅有一条路径.邻居鲍伯要约翰来导航,但约翰丢了农场的地图,他只得从电脑的备份中修复了.每一条道路的信息如下: 从农场23往南经距离10到达农场17 从农场1往东经距离7到达农

HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形dp, 对于每条链u,v,w,我们只在lca(u,v)的顶点上处理它 让dp[i]表示以i为根的指数的最大值,sum[i]表示dp[vi]的和(vi为i的儿子们) 则i点有两种决策,一种是不选以i为lca的链,则dp[i]=sum[i]. 另一种是选一条以i为lca的链,那么有转移方程:dp[i]=