2014多校05场第6题
挺棒的树dp
题目每次询问给两个节点,问不在这两个节点的路径上的最小节点编号是多少
首先,如果两个节点的路径不经过点1,显然最小编号是1
如果经过1的话,那么以1为根,这两个点到1的路径肯定来自不同的子树,假设这两个点分别是a和b
然后最小的节点就是{a所在子树中去掉a到1的路径最小的点,b所在子树中去掉b到1的路径最小的点,其他子树中最小的点}中最小的点
每个点属于哪个子树很好处理,每个子树最小的点是谁也很好处理
然后就是处理“点x所在子树中除去x到根的路径外的最小的节点”
这个东西是{点x的所有子树中的最小节点,从根走过来一路上的分支子树中的最小节点}中的最小节点
而{从根走到x一路上的分支子树中的最小节点}是{从根走到x的父亲一路上的分支子树中的最小节点}和{x的父亲除了x所在子树的所有子树的最小节点}中的最小
然后问题就解决了
#include <stdio.h>
#include <string>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <limits.h>
#include <math.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
typedef pair<int,int> PII;
typedef long long LL;
#define CLR(x,y) memset(x,y,sizeof(x));
#define PB push_back
#define MP make_pair
#define INF 0x3f3f3f3f
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int N = 1000000+20;
inline int Min(int a,int b){
return a < b ? a : b;
}
int get() {
char c;
while(c=getchar(),(c<'0'||c>'9')&&(c!='-'));
bool flag=(c=='-');
if(flag)
c=getchar();
int x=0;
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
return flag?-x:x;
}
void output(long long x) {
if(x<0) {
putchar('-');
x=-x;
}
int len=0,data[20];
while(x) {
data[len++]=x%10;
x/=10;
}
if(!len)
data[len++]=0;
while(len--)
putchar(data[len]+'0');
putchar('\n');
}
struct node
{
int v,w;
int nxt;
}edge[N << 1];
int head[N],idx;
void init()
{
CLR(head, -1);
idx = 0;
}
void add_edge(int u,int v,int w)
{
edge[idx].v = v;
edge[idx].w = w;
edge[idx].nxt = head[u];
head[u] = idx ++;
edge[idx].v = u;
edge[idx].w = w;
edge[idx].nxt = head[v];
head[v] = idx++;
}
int n,q;
int tot;
int bel[N];
int fa[N];
int mm[N];
int xm[N][2];
int sm[N];
multiset<int> mii;
multiset<int>::iterator ite;
void update(int s,int val)
{
if(val < xm[s][0]){
xm[s][1] = xm[s][0];
xm[s][0] = val;
}else if(val < xm[s][1]){
xm[s][1] = val;
}
}
int search(int s,int mark)
{
bel[s] = mark;
for(int i = head[s]; ~i ; i = edge[i].nxt){
int v = edge[i].v;
if(v != fa[s]){
fa[v] = s;
update(s, Min(search(v,mark),v));
}
}
return xm[s][0];
}
void dfs(int s)
{
for(int i = head[s]; ~i ; i = edge[i].nxt){
int v = edge[i].v;
if(v != fa[s]){
sm[v] = Min(sm[s],(Min(xm[v][0],v)==xm[s][0]?xm[s][1]:xm[s][0]));
mm[v] = Min(sm[v],xm[v][0]);
dfs(v);
}
}
}
void solve()
{
CLR(fa, -1);
CLR(xm, 0x3f);
CLR(sm, 0x3f);
CLR(mm, 0x3f);
bel[1] = n+1;
tot = 0;
int cnt = 0;
for(int i = head[1]; ~i ; i = edge[i].nxt){
int v = edge[i].v;
fa[v] = 1;
search(v,v);
dfs(v);
mm[v] = Min(sm[v],xm[v][0]);
cnt ++;
}
mii.clear();
for(int i = head[1]; ~i ; i = edge[i].nxt){
int v = edge[i].v;
int val = Min(v,mm[v]);
mii.insert(val);
if(mii.size() > 3){
ite = mii.end();
ite--;
mii.erase(ite);
}
}
}
int work(int u,int v)
{
if(bel[u] == bel[v])return 1;
int a = Min(bel[u],mm[bel[u]]);
int b = Min(bel[v],mm[bel[v]]);
int m = 0;
for(ite = mii.begin();ite != mii.end() ;ite++){
int val = *ite;
if(val == a){
a = -1;
}else{
if(val == b){
b = -1;
}else{
m = val;
break;
}
}
}
return Min(m,Min(mm[u],mm[v]));
}
int main()
{
// freopen("/Users/minli/Documents/Developer/Testebd/cpp/cpp/input.txt", "r", stdin);
// freopen("/Users/minli/Documents/Developer/Testebd/cpp/cpp/output.txt", "w", stdout);
while(~scanf("%d%d",&n,&q)){
init();
for(int i = 0 ; i < n-1 ; i ++){
int a,b;
a = get();
b = get();
add_edge(a, b, 1);
}
solve();
int ans = -1;
while(q--){
int a,b;
a = get();
b = get();
if(ans != -1){
a = a ^ ans;b = b ^ ans;
}
ans = work(a,b);
output(ans);
}
}
return 0;
}