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 那么特殊处理一下。用map维护一下除了u节点下的子树。1的最小子孙节点
#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 1000000
#define N 100050
struct Edge{
int from, to, dis, nex;
}edge[5*N];
int head[N],edgenum,dis[N],fa[N][20],dep[N]; //fa[i][x] 是i的第2^x个父亲(假设超过范围就是根)
void add(int u,int v,int w){
Edge E={u,v,w,head[u]};
edge[edgenum] = E;
head[u]=edgenum++;
}
void bfs(int root){
queue<int> q;
fa[root][0]=root;dep[root]=0;dis[root]=0;
q.push(root);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=1;i<20;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=head[u]; ~i;i=edge[i].nex){
int v=edge[i].to;if(v==fa[u][0])continue;
dep[v]=dep[u]+1;dis[v]=dis[u]+edge[i].dis;fa[v][0]=u;
q.push(v);
}
}
}
int move(int x,int y){//把x移动到y以下
int D = dep[x] - dep[y]-1;
while(D){
int z = (int)(log10(1.0*D)/log10(2.0));
x = fa[x][z];
D-=1<<z;
}
return x;
}
int Lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=0;i<20;i++)if((dep[x]-dep[y])&(1<<i))x=fa[x][i];
if(x==y)return x;
for(int i=19;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
void init(){memset(head, -1, sizeof head); edgenum = 0;}
int son[N][3], Fa[N];
//0是最小 1是子孙最小 2是次小
void dfs(int u,int father){
Fa[u] = father;
son[u][0] = son[u][1] = son[u][2] = inf;
for(int i = head[u]; ~i; i = edge[i].nex){
int v = edge[i].to; if(v==father)continue;
dfs(v,u);
if(v<son[u][0])
son[u][2] = son[u][0], son[u][0] = v;
else son[u][2] = min(son[u][2], v);
son[u][1] = min(son[u][1], son[v][1]);
}
son[u][1] = min(son[u][1], son[u][0]);
}
map<int,int>mp;
bool work(int x,int y){
int lca = Lca(x,y), son1, son2;
if(lca==y) {
x = move(x,y);
son1 = son[y][0];
if(son1 == x) son1 = son[y][2];
son1 = min(son1, Fa[y]);
if(y==1) {
son2 = mp[x];
}
else son2 = 1;
} else {
son1 = son[y][0];
son2 = son[y][1];
}
if(son1==inf||son2==inf)return false;
printf("%d %d\n",son1,son2);
return true;
}
int n;
int main(){
int i,j,u,v,T,que;scanf("%d",&T);
while(T--){
init();
scanf("%d %d",&n,&que);
for(i = 1; i < n; i++) {
scanf("%d %d",&u,&v);
add(u,v,1);
add(v,u,1);
}
bfs(1);
dfs(1,1);
Fa[1] = inf;
mp.clear();
int fir = inf, sec = inf;
for(i = head[1]; ~i; i = edge[i].nex){
v = edge[i].to;
mp[v] = inf;
if(v<fir)sec = fir, fir = v;
else sec = min(sec, v);
} for(i = head[1]; ~i; i = edge[i].nex){
v = edge[i].to;
if(v!=fir)mp[v] = fir;
else mp[v] = sec;
}
fir = inf; sec = inf;
for(i = head[1]; ~i; i = edge[i].nex){
v = edge[i].to;
if(son[v][1]<fir)sec = fir, fir = son[v][1];
else sec = min(sec, son[v][1]);
}
for(i = head[1]; ~i; i = edge[i].nex){
v = edge[i].to;
if(son[v][1]!=fir)
mp[v] = min(mp[v], fir);
else
mp[v] = min(mp[v], sec);
}
while(que--){
scanf("%d %d",&u,&v);
if(work(u,v)==false)
puts("no answers!");
}
puts("");
}
return 0;
}
HDU 4008 Parent and son LCA+树形dp的更多相关文章
- HDU 4008 Parent and son
树形DP+LCA+思路.这题可真是有点难度......所以准备详细写一下题解. 题意:给一颗无根树,有Q次询问,每次询问指定一个根节点X,然后让你计算Y节点的儿子和子孙中,编号最小的节点是多少. 我们 ...
- 可恶!学了这么久的LCA,联考的题目却是LCA+树形DP!!!可恶|!!!这几天想学学树形DP吧!先来一道入门题HDU 1520 Anniversary party
题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...
- poj3417 LCA + 树形dp
Network Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 4478 Accepted: 1292 Descripti ...
- HDU 1054 Strategic Game(最小点覆盖+树形dp)
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=106048#problem/B 题意:给出一些点相连,找出最小的点数覆盖所有的 ...
- HDU 1520.Anniversary party 基础的树形dp
Anniversary party Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others ...
- HDU 5977 Garden of Eden (树形dp+快速沃尔什变换FWT)
CGZ大佬提醒我,我要是再不更博客可就连一月一更的频率也没有了... emmm,正好做了一道有点意思的题,就拿出来充数吧=.= 题意 一棵树,有 $ n (n\leq50000) $ 个节点,每个点都 ...
- HDU 3586 Information Disturbing(二分+树形dp)
http://acm.split.hdu.edu.cn/showproblem.php?pid=3586 题意: 给定一个带权无向树,要切断所有叶子节点和1号节点(总根)的联系,每次切断边的费用不能超 ...
- HDU 5682 zxa and leaf 二分 树形dp
zxa and leaf 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5682 Description zxa have an unrooted t ...
- HDU 6201 2017沈阳网络赛 树形DP或者SPFA最长路
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6201 题意:给出一棵树,每个点有一个权值,代表商品的售价,树上每一条边上也有一个权值,代表从这条边经过 ...
随机推荐
- 2.RDD的基本操作
有些时候,我不太喜欢介绍相关概念什么的(其实是你懒吧),而是喜欢直接介绍用法. 所以RDD是什么这里也不再介绍了,可以自行百度,下面直接介绍rdd的一些操作 from pyspark import S ...
- python数据类型-----列表
今天来总结下python3.4版本列表的一些操作方法. 列表(list): 1.列表就像一个线性容器,但是比C++的 lis t扩展多得多,列表里的元素可以是相同类型,也可以包含各种类型,比如列表里嵌 ...
- [ 总结 ] vsftpd 虚拟用户配置
需求:在不更改目录权限的前提下,ftp用户对目录里的文件拥有所有权. [root@server2 ~]# yum install vsftpd -y [root@server2 ~]# cd /etc ...
- 学习OpenResty编程
1.Windows版本的下载位置 https://github.com/LomoX-Offical/nginx-openresty-windows Linux下OpenResty的下载和安装 http ...
- JS监听页面滚动到底部事件
废话不说,直接上代码,放心我这个是最好的,直接放到js脚本里,直接生效: $(window).scroll(function(){ var scrollTop = $(this).scrollTop( ...
- PHP常用函数及其注释
<?php //===============================时间日期=============================== //y返回年最后两位,Y年四位数,m月份数字 ...
- Python timedelta模块 时间增减用法
timedalte 是datetime中的一个对象,该对象表示两个时间的差值 构造函数:datetime.timedelta(days=0, seconds=0, microseconds=0, mi ...
- BZOJ 1185: [HNOI2007]最小矩形覆盖-旋转卡壳法求点集最小外接矩形(面积)并输出四个顶点坐标-备忘板子
来源:旋转卡壳法求点集最小外接矩形(面积)并输出四个顶点坐标 BZOJ又崩了,直接贴一下人家的代码. 代码: #include"stdio.h" #include"str ...
- 训练指南 UVA - 11354(最小生成树 + 倍增LCA)
layout: post title: 训练指南 UVA - 11354(最小生成树 + 倍增LCA) author: "luowentaoaa" catalog: true ma ...
- 并查集【CF731C】Socks
Description 有\(n\)只袜子,\(k\)种颜色,在\(m\)天中,问最少修改几只袜子的颜色,可以使每天要穿的袜子颜色相同. Input 第一行\(n,m,k\)分别对应题目描述. 接下来 ...