这道题的题意其实有点略晦涩,定义f(a,b)为 minimum of vertices not on the path between vertices a and b. 其实它加一个minimum index of vertices应该会好理解一点吧。看了一下题解,还有程序,才理清思路。

首先比较直接的是如果两点的路径没有经过根节点1的话,那么答案就直接是1,否则的话就必然有从根节点出发的两条路径,题解里说的预处理出f[u]表示不在根节点到u的路径上的点的最小值,然后取f[u]和f[v]的最小值看了我半天。因为如果是这样的话,那么下面这个图不就可以轻易cha掉这种做法?

1->2  1->3  2->4  4->6  4->7  3->5  5->8  5->9

询问(6,8)的时候显然f(6)是3,f(8)是2,那么输出的答案就会是2,但实际上应该输出的是7。

后来仔细探究了才发现,f[u]存的只是  从不在根节点到u的路径的最小值(其中不包括根节点到别的子节点的路径),换言之上面的f[6]里只存了7,f[8]里只存了9,所以min(7,9)=7。

但是这个时候我们可能就会出错了,因为如果根节点如果连出去有第三条路径的话,那么这条路径的最小值我们是没有包含到的,所以对于根节点我们要存它最小值的子树,还有也要存对于每个节点它来自于哪个子树。

剩下的就是一个类似树dp的过程了。

然后题目还温馨提示了可能会超时,可能要写个输入挂什么的,所以写邻接表的可能都不能写vector的形式了吧。

#pragma warning(disable:4996)
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std; #define maxn 1005000
#define inf 0x3f3f3f3f int child[maxn][4];
int subtree[maxn];
int path[maxn];
int fa[maxn];
int bel[maxn];
int que[maxn];
int qh, qt;
int n, nQ; int head[maxn];
int nxt[maxn<<1];
int vv[maxn<<1];
int tot; void add_Edge(int u,int v)
{
vv[tot] = v; nxt[tot] = head[u]; head[u] = tot++;
} void bfs()
{
qh = qt = 0;
que[qt++] = 1; fa[1] = -1;
while (qh < qt){
int u = que[qh++];
for (int i = head[u]; ~i; i=nxt[i]){
int v = vv[i];
if (v == fa[u]) continue;
fa[v] = u;
que[qt++] = v;
}
}
for (int i = 0; i <= n; ++i){
for (int j = 0; j < 4; ++j){
child[i][j] = inf;
}
}
for (int i = n - 1; i >= 0; --i){
int u = que[i]; subtree[u] = u;
for (int j = head[u]; ~j; j=nxt[j]){
int v = vv[j];
if (v == fa[u]) continue;
child[u][3] = subtree[v];
sort(child[u], child[u] + 4);
}
subtree[u] = min(subtree[u], child[u][0]);
} qh = qt = 0;
for (int i = head[1]; ~i; i=nxt[i]){
int v = vv[i];
que[qt++] = v;
bel[v] = subtree[v];
path[v] = inf;
}
while (qh < qt){
int u = que[qh++];
for (int i = head[u]; ~i; i=nxt[i]){
int v = vv[i];
if (v == fa[u]) continue;
bel[v] = bel[u];
if (subtree[v] == child[u][0]){
path[v] = min(path[u], child[u][1]);
}
else{
path[v] = min(path[u], child[u][0]);
}
que[qt++] = v;
}
path[u] = min(path[u], child[u][0]);
}
} int query(int qu, int qv){
if (qu > qv) swap(qu, qv);
if (qu != 1 && bel[qu] == bel[qv]) return 1;
int i = 0;
while (child[1][i] == bel[qu] || child[1][i] == bel[qv]){
i++;
}
int ret = qu == 1 ? path[qv] : min(path[qu], path[qv]);
ret = min(ret, child[1][i]);
return ret;
} inline void scan(int &n)
{
char cc;
for (; cc = getchar(), cc<'0' || cc>'9';);
n = cc - '0';
for (; cc = getchar(), cc >= '0'&&cc <= '9';)
n = n * 10 + cc - '0';
} int main()
{
while (cin >> n >> nQ){
tot = 0; memset(head, -1, sizeof(head));
int ui, vi;
for (int i = 0; i < n - 1; ++i){
//scan(ui); scan(vi);
scanf("%d%d", &ui, &vi);
add_Edge(ui, vi);
add_Edge(vi, ui);
}
bfs();
int last = 0;
for (int i = 0; i < nQ; ++i){
//scan(ui); scan(vi);
scanf("%d%d", &ui, &vi);
ui ^= last; vi ^= last;
printf("%d\n", last=query(ui, vi));
}
}
return 0;
}

HDU4916 Count on the path(树dp??)的更多相关文章

  1. hdu4916 Count on the path

    调了好久.... •把树视为以1为根的有向树,然后将1删除 •原树变为一个森林,并且任一棵树的根节点均为原树中1的子节点 •只需要考虑最小编号前3小的三棵树 •记f[x][y]为去掉x和y两棵树后的最 ...

  2. 【HDU 5647】DZY Loves Connecting(树DP)

    pid=5647">[HDU 5647]DZY Loves Connecting(树DP) DZY Loves Connecting Time Limit: 4000/2000 MS ...

  3. Count on the path

    Count on the path Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  4. CF456D A Lot of Games (字典树+DP)

    D - A Lot of Games CF#260 Div2 D题 CF#260 Div1 B题 Codeforces Round #260 CF455B D. A Lot of Games time ...

  5. Codeforces 219D. Choosing Capital for Treeland (树dp)

    题目链接:http://codeforces.com/contest/219/problem/D 树dp //#pragma comment(linker, "/STACK:10240000 ...

  6. HDU4276 The Ghost Blows Light SPFA&&树dp

    题目的介绍以及思路完全参考了下面的博客:http://blog.csdn.net/acm_cxlove/article/details/7964739 做这道题主要是为了加强自己对SPFA的代码的训练 ...

  7. Tsinsen A1219. 采矿(陈许旻) (树链剖分,线段树 + DP)

    [题目链接] http://www.tsinsen.com/A1219 [题意] 给定一棵树,a[u][i]代表u结点分配i人的收益,可以随时改变a[u],查询(u,v)代表在u子树的所有节点,在u- ...

  8. HDU 3016 Man Down (线段树+dp)

    HDU 3016 Man Down (线段树+dp) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Ja ...

  9. bzoj 3572世界树 虚树+dp

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

随机推荐

  1. [Letcode] 1. Two Sum

    Given an array of integers, return indices of the two numbers such that they add up to a specific ta ...

  2. golang:slice陷阱

    slice陷阱,slice底层指向某个array,在赋值后容易导致array长期被引用而无法释放

  3. Go defer延迟执行

    defer用于延迟执行,可以类比于java或c++中的析构函数. 查看一段示例代码: func Contents(filename string) (string, error) { //打开文件 f ...

  4. kafka中server.properties配置文件参数说明

    转自:http://blog.csdn.net/lizhitao/article/details/25667831 参数 说明(解释) broker.id =0 每一个broker在集群中的唯一表示, ...

  5. LinqToExcel: LINQ查询Excel电子表格

    Linq的强大人所共知,能不能将Linq扩展到读取excel呢? 答案当然是肯定的. LinqToExcel就是一个实现了使用Linq语法查询excel表格的.net开源类库. 在nuget搜索下载安 ...

  6. C++ this指针详解

       C++this指针操作 在这里总结一下this 指针的相关知识点. 首先,我们都知道类的成员函数可以访问类的数据(限定符只是限定于类外的一些操作,类内的一切对于成员函数来说都是透明的),那么成员 ...

  7. 硬件相关-ADC原理(未完成)

    一.模数转换的一般步骤: 1)采样和保持 为了把模拟信号转换成对应的数字信号,必须首先将模拟量每隔一定时间抽取一次样值,使时间上连续变化的模拟量变为一个时间上断续变化的模拟量,这个过程称为采样. 为了 ...

  8. 桥接模式和NAT模式

    linux的目录结构 配置ip三种 模式 桥接模式 nat模式(VMnet8) 配置网关 DHCP动态分配IP设置 linux的目录结构 配置ip三种 模式 桥接模式 (1) 设置主系统的" ...

  9. 【BZOJ 2324】 [ZJOI2011]营救皮卡丘

    Description 皮卡丘被火箭队用邪恶的计谋抢走了!这三个坏家伙还给小智留下了赤果果的挑衅!为了皮卡丘,也为了正义,小智和他的朋友们义不容辞的踏上了营救皮卡丘的道路. 火箭队一共有N个据点,据点 ...

  10. Java内部实现的观察者模式小记

    假如Admin要观察User的工资变化,当User的工资增加或者减少时,都会引起Admin输出相应的信息. 定义观察者接口:MyObserver.java package cn.liuning.wat ...