Count on the path
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 378 Accepted Submission(s): 113
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.
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.
For each queries, a single number denotes the value.
題意:給你一棵樹,最多有1e6個點。不斷詢問a->b外的最小點。
基本仿照gxx的標程來寫的,感覺學到了很多。這題主要是考一些樹上的細膩的操作。
思路見註釋
代碼:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <functional>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include <ctime>
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF 1e9
#define MAXN 21
const int maxn = 1000005;
#define mod 1000000007
#define eps 1e-7
#define pi 3.1415926535897932384626433
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define scan(n) scanf("%d",&n)
#define scanll(n) scanf("%I64d",&n)
#define scan2(n,m) scanf("%d%d",&n,&m)
#define scans(s) scanf("%s",s);
#define ini(a) memset(a,0,sizeof(a))
#define out(n) printf("%d\n",n)
//ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b);}
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int q[maxn];
int path[maxn]; //path[i]記錄表示在i所在的子樹中(以1爲根),除i到1這條路徑外的最小值
int child[maxn][4]; //child[i][0]表示以i爲根且不包括i的樹的最小點,child[i][1]爲次小,child[i][2]爲第三小
int fa[maxn];
int belong[maxn]; //belong[i]表示i所在的子樹(以1爲根)的最小值,可用來快速判斷兩點是否位於同一子樹
int subtree[maxn];//subtree[i]表示以i爲根(包括i)的子樹的最小值
vector<int> G[maxn]; //鄰接表
int n,m;
int next_int()
{
int result = 0;
char c = getchar();
while (!isdigit(c)) {
c = getchar();
}
while (isdigit(c)) {
result = result * 10 + c - '0';
c = getchar();
}
return result;
}
int query(int a,int b)
{
if(a > b) swap(a,b);
if(a != 1 && (belong[a] == belong[b])) return 1; //若兩點位於同一子樹,則不經過1
int i = 0;
while(child[1][i] == belong[a] || child[1][i] == belong[b]) i++; //找出除a,b所在子樹外最小的點
int ans = a == 1 ? path[b] : min(path[a], path[b]); //a,b所在子樹最小的點(a->1,b->1的路徑除外)
ans = min(ans, child[1][i]);
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
#endif
while(~scanf("%d%d",&n,&m))
{
int a,b;
rep(i,n+1) G[i].clear();
rep(i,n-1)
{
a = next_int();
b = next_int();
G[a].push_back(b); //用了vector保存鄰接表,不斷pb g++T了,用C++過了
G[b].push_back(a);
}
int head = 0, tail = 0;
q[tail++] = 1;
fa[1] = -1;
while(head < tail)
{
int u = q[head++];
for(int i = 0;i <(int)G[u].size(); i++)
{
int v = G[u][i];
if(v == fa[u]) continue;
fa[v] = u;
q[tail++] = v;
}
}
rep1(i,n) rep(j,4) child[i][j] = INF;
for(int i = tail-1; i >= 0; i--)
{
int v = q[i];
subtree[v] = min(child[v][0], v);
int u = fa[v];
if(u != -1)
{
child[u][3] = subtree[v];
sort(child[u], child[u] + 4);
//path[v] = min(child[u][0]
}
}
head = tail = 0;
for(int i = 0;i < (int)G[1].size(); i++)
{
int u = G[1][i];
belong[u] = subtree[u];
path[u] = INF;
q[tail++] = u;
}
path[1] = INF;
belong[1] = -1;
while(head < tail)
{
int u = q[head++];
for(int i = 0;i < (int)G[u].size(); i++)
{
int v = G[u][i];
if(v == fa[u]) continue;
belong[v] = belong[u];
path[v] = min(path[u], child[u][subtree[v] == child[u][0]]);
q[tail++] = v;
}
path[u] = min(path[u], child[u][0]);
}
int last = 0;
while(m--)
{
a = next_int();
b = next_int();
a ^= last;
b ^= last;
int ans = query(a,b);
last = ans;
printf("%d\n",ans);
}
}
return 0;
}