HDU 4916 树形dp

Count on the path

Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)

Total Submission(s): 92    Accepted Submission(s): 10

Problem Description

bobo has a tree, whose vertices are conveniently labeled by 1,2,…,n.

Let f(a,b) be the minimum of vertices not on the path between vertices a and b.

There are q queries (ui,vi) for the value of f(ui,vi). Help bobo answer them.

Input

The input consists of several tests. For each tests:

The first line contains 2 integers n,q (4≤n≤106,1≤q≤106). Each of the following (n - 1) lines contain 2 integers ai,bi denoting an edge between vertices ai and bi (1≤ai,bi≤n).
Each of the following q lines contains 2 integer u′i,v′i (1≤ui,vi≤n).

The queries are encrypted in the following manner.

u1=u′1,v1=v′1.

For i≥2, ui=u′i⊕f(ui - 1,vi - 1),vi=v′i⊕f(ui-1,vi-1).

Note ⊕ denotes bitwise exclusive-or.

It is guaranteed that f(a,b) is defined for all a,b.

The task contains huge inputs. `scanf` in g++ is considered too slow to get accepted. You may (1) submit the solution in c++; or (2) use hand-written input utilities.

Output

For each tests:

For each queries, a single number denotes the value.

Sample Input

4 1
1 2
1 3
1 4
2 3
5 2
1 2
1 3
2 4
2 5
1 2
7 6

Sample Output

4
3
1

Author

Xiaoxu Guo (ftiasch)

给定一棵树,求不经过路径的最小标号。

把1作为根,然后增加不经过1,那么答案直接为1,否则就是预处理,

数据规模非常大,所以仅仅能用bfs,而且须要加读写外挂,具体过程代码具体解释。

代码:

/* ***********************************************
Author :rabbit
Created Time :2014/8/6 10:44:17
File Name :5.cpp
************************************************ */
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <string>
#include <time.h>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
typedef long long ll;
int fun(){
       char ch;int flag=1,a=0;
       while(ch=getchar())if((ch>='0'&&ch<='9')||ch=='-')break;
       if(ch=='-')flag=-1;else a=ch-'0';
       while(ch=getchar()){
              if(ch>='0'&&ch<='9')a=10*a+ch-'0';
              else break;
       }
       return flag*a;
}
const int maxn=1001000;
int head[maxn],tol;
int subtree[maxn];//子树最小标号
int belong[maxn];//所在的与根节点1相连的子树最小标号。
int child[maxn][4];//儿子子树前4小。
int que[maxn];//广搜队列。
int path[maxn];//path[u]代表u所在的在根节点1的儿子的子树中从根节点到u路径以外的最小标号。
int fa[maxn];//父亲标号。
int dep[maxn];//深度数组
struct Edge{
	int next,to;
}edge[2*maxn];
void addedge(int u,int v){
	edge[tol].to=v;
	edge[tol].next=head[u];
	head[u]=tol++;
}
int main()
{
     //freopen("data.in","r",stdin);
     //freopen("data.out","w",stdout);
     int n,m;
	 while(~scanf("%d%d",&n,&m)){
		 memset(head,-1,sizeof(head));tol=0;
		 for(int i=1;i<n;i++){
			 int u,v;
			 u=fun();v=fun();
			 addedge(u,v);
			 addedge(v,u);
		 }
		 int front=0,rear=0;
		 dep[1]=0;fa[1]=-1;
		 que[rear++]=1;
		 while(front!=rear){
			 int u=que[front++];
			 for(int i=head[u];i!=-1;i=edge[i].next){
				 int v=edge[i].to;
				 if(v==fa[u])continue;
				 dep[v]=dep[u]+1;
				 fa[v]=u;
				 que[rear++]=v;
			 }
		 }
		 for(int i=1;i<=n;i++)
			 for(int j=0;j<4;j++)
				 child[i][j]=INF;
		 for(int i=rear-1;i>=0;i--){
			 int u=que[i];
			 subtree[u]=min(u,child[u][0]);
			 int p=fa[u];
			 if(p==-1)continue;
			 child[p][3]=subtree[u];
			 sort(child[p],child[p]+4);
		 }
		 front=0,rear=0;
		 path[1]=INF;
		 belong[1]=-1;
		 for(int i=head[1];i!=-1;i=edge[i].next){
			 int u=edge[i].to;
			 path[u]=INF;
			 belong[u]=subtree[u];
			 que[rear++]=u;
		 }
		 while(front!=rear){
			 int u=que[front++];
			 for(int i=head[u];i!=-1;i=edge[i].next){
				 int v=edge[i].to;
				 if(v==fa[u])continue;
				 path[v]=min(path[u],child[u][subtree[v]==child[u][0]]);
				 belong[v]=belong[u];
				 que[rear++]=v;
			 }
			 path[u]=min(path[u],child[u][0]);//u的儿子子树的最小标号。
		 }
		 int last=0;
		 while(m--){
			 int u,v;
			 u=fun();v=fun();
			 u^=last;v^=last;
			 if(u>v)swap(u,v);
			 if(u!=1&&belong[u]==belong[v])last=1;//假设不经过1,而且属于同一个根节点的儿子的子树,答案直接为1
			 else{
				 int i=0;
				 while(child[1][i]==belong[u]||child[1][i]==belong[v])i++;//把包括u,v的儿子子树跳过。
				 last=u==1?path[v]:min(path[u],path[v]);//路径分为两段,取最小值。
				 last=min(last,child[1][i]);//出去u,v所在的子树以外的最小值。
			 }
			 printf("%d\n",last);
		 }
	 }
     return 0;
}
时间: 2024-09-29 16:35:47

HDU 4916 树形dp的相关文章

hdu 4123 树形DP+RMQ

http://acm.hdu.edu.cn/showproblem.php?pid=4123 Problem Description Bob wants to hold a race to encourage people to do sports. He has got trouble in choosing the route. There are N houses and N - 1 roads in his village. Each road connects two houses,

hdu 1250 树形DP

Anniversary party Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Appoint description:  System Crawler  (2014-07-27) Description There is going to be a party to celebrate the 80-th Anniversary of the Ural St

hdu 4276(树形dp)

题意:带权树上有起点终点每个点上有宝藏,一个人只有T分钟要从起点到重点,问你最多能收集多少宝藏. 思路:树形dp,首先判断能不能走到终点,然后把路径上的边权变为0时间减去所有边权.dp[v][j]表示从v出发回到v话费j分钟最多能收集到的宝藏. dp[v][j] = max(dp[v][j], dp[x][k] + dp[v][j-k-2*val]); 被G++卡了好长时间,换成c++就过了. 代码如下: 1 #include <stdio.h> 2 #include <string.h

hdu 5148 树形dp+分组背包问题

http://acm.hdu.edu.cn/showproblem.php?pid=5148 Problem Description Long long ago,there is a knight called JayYe.He lives in a small country.This country is made up of n cities connected by n-1 roads(that means it's a tree).The king wants to reward Ja

HDU 1520 树形dp裸题

1.HDU 1520  Anniversary party 2.总结:第一道树形dp,有点纠结 题意:公司聚会,员工与直接上司不能同时来,求最大权值和 #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #define max(a,b) a>b?a:b using nam

hdu 3586 树形dp+二分

题目大意:给定n个敌方据点,1为司令部,其他点各有一条边相连构成一棵 树,每条边都有一个权值cost表示破坏这条边的费用,叶子节点为前线.现要切断前线和司令部的联系,每次切断边的费用不能超过上限limit,问切断所 有前线与司令部联系所花费的总费用少于m时的最小limit.1<=n<=1000,1<=m<=100万 题目要问的是最小的最大限制,必然二分答案 然后对于每一个值,树形DP判定是否可行 dp[i]表示要切断以i为根的其它所有子树的最小代价. 其中设定叶子结点的代价为无穷大

HDU 1561 树形DP入门

The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 6011    Accepted Submission(s): 3555 Problem Description ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝物

hdu 1561 树形dp

又一道树形dp,发现其实树形dp长得都挺像的. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int INF = -9999999; 7 const int N = 201; 8 int dp[N][N]; 9 int head[N]; 10 int value[N]; 11 int n, m, e; 12 13 void i

hdu 1011 树形dp+背包

题意:有n个房间结构可看成一棵树,有m个士兵,从1号房间开始让士兵向相邻的房间出发,每个房间有一定的敌人,每个士兵可以对抗20个敌人,士兵在某个房间对抗敌人使无法走开,同时有一个价值,问你花费这m个士兵可以得到的最大价值是多少 分析:树形dp,对于点u,dp[u][j]表示以u为根的树消耗j个士兵得到的最大值,dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[son][k]+val[u]) 注意是无向图,vis位置不能随便放,且注意dp不能直接+val,因为这样根节点就加不