hdu 4916 Count on the path

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


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)
 

Source
 

題意:給你一棵樹,最多有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;
}



發佈了52 篇原創文章 · 獲贊 1 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章