hdu 5678 ztr loves trees(求子树第k大 线段树套主席树)

ztr loves trees

Problem Description
Super Deity ztr likes trees from childhood,CCTV-children:"The apple on the apple tree.You and I under the apple tree.Play games in front of the apple tree.So many happiness".

One day,qzh visit ztr to ask some questions.To give a tree with a root,each vertex has a value.Each time query the median of a subtree.

ztr said:this is a water problem,do you do it?But qzh show cannot help but want you who is also a Super Deity to help him.Could you help him?
 

Input
There are T test cases. The first line of input contains an positive integer T indicating the number of test cases.

For each test case:

Each line contains two positive integer n,m.indicating the number of vetrex and the number of query times.
The next line contains n numbers, the ith number indicating the value of vertex i.
The next n-1 lines,each line contains two numbers u and v,indicating there is a edge form u to v.

The next m lines, each line contains a numbers x.indicating query the median of subtree x.

1<=T<=3,1<=n<=105,1<=m<=106,1<=u<=v<=n,1<=val<=109.
The vetrex 1 is the root of the tree.Guarantee input a tree with a root.
 

Output
For each test case:print a line.To avoid huge output,you should hash each answer first,then print it.

The method to hash:a[i] indicates the ith query result, ans=a[i]10mimod1,000,000,007 Round to the nearest tenth
 

Sample Input
 
    
1 5 3 1 2 3 4 5 1 2 2 3 3 4 4 5 1 2 3
 

Sample Output
 
    
339.  

solution:
此题要求子树第k大,那么我们可以用dfs序预处理出来以i为根的子树区间为l[i]~r[i],之后就是用主席树套线段树求区间第k大(模板),但还需要做一些处理,若是偶数,则中位数还有可能有小数,因此用pair解决即可,详细请看代码,欢迎讨论~
#include 
#include 
#include 
#include
using namespace std;
typedef long long ll;
#define pii pair 
#define xx first
#define yy second
using namespace std;
const int maxn = 110000;
const int mod = 1e9 + 7;
int T[maxn], num[maxn], san[maxn], ls[maxn * 20], rs[maxn * 20], sum[maxn * 20], l[maxn], r[maxn], a[maxn];
pii res[maxn];
int tot, rt, dfsxu, cc;
int head[maxn];
struct edge {
	int to, next;
} e[maxn * 2];
void add(int u, int v) 
{
	e[cc].to = v; e[cc].next = head[u];head[u] = cc++;
}
int sz[maxn];
void dfs(int u, int fa) //dfs序
{
	sz[u] = 1;
	l[u] = ++dfsxu;
	num[dfsxu] = san[dfsxu] = a[u];
	for (int i = head[u]; i!=-1; i = e[i].next) 
	{
		int v = e[i].to;
		dfs(v, u);
		sz[u] += sz[v];
	}
	r[u] = dfsxu;
}
void Build(int l, int r, int &rt)
{
	rt = ++tot;
	sum[rt] = 0;
	if (l == r) return;
	int m = (l + r) >> 1;
	Build(l, m, ls[rt]);
	Build(m + 1, r, rs[rt]);
}
void Update(int last, int p, int l, int r, int &rt)
{
	rt = ++tot;
	ls[rt] = ls[last];
	rs[rt] = rs[last];
	sum[rt] = sum[last] + 1;
	if (l == r) return;
	int m = (l + r) >> 1;
	if (p <= m) Update(ls[last], p, l, m, ls[rt]);
	else  Update(rs[last], p, m + 1, r, rs[rt]);
}
int Query(int ss, int tt, int l, int r, int k)
{
	if (l == r) return l;
	int m = (l + r) >> 1;
	int cnt = sum[ls[tt]] - sum[ls[ss]];
	if (k <= cnt)
		return Query(ls[ss], ls[tt], l, m, k);
	else
		return Query(rs[ss], rs[tt], m + 1, r, k - cnt);
}
void solve()
{
	tot = 0;
	sort(san + 1, san + dfsxu + 1);
	int cnt=unique(san + 1, san + dfsxu + 1) - san - 1;
	Build(1, cnt, T[0]);
	for (int i = 1; i <= dfsxu; i++) num[i] = lower_bound(san + 1, san + cnt + 1, num[i]) - san;
	for (int i = 1; i <= dfsxu; i++) Update(T[i - 1], num[i], 1, cnt, T[i]);
	for (int i = 1; i <= dfsxu; i++) 
		if (sz[i] & 1) res[i] = pii(san[Query(T[l[i] - 1], T[r[i]], 1, cnt, sz[i] / 2 + 1)], 0);
		else {
			int tmp = san[Query(T[l[i] - 1], T[r[i]], 1, cnt, sz[i] / 2)] + san[Query(T[l[i] - 1], T[r[i]], 1, cnt, sz[i] / 2 + 1)];
			res[i] = pii(tmp / 2, tmp & 1);
		}
}
void init()
{
	cc = 0; dfsxu = 0; tot = 0;
	memset(head, -1, sizeof head);
}
int main()
{
	int T,n, m, u, v, x;;
	scanf("%d", &T);
	while (T--)
	{
		init();
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; i++)
			scanf("%d", &a[i]);
		for (int i = 1; i < n; i++) 
		{
			scanf("%d%d", &u, &v);
			add(u, v);
		}
		dfs(1, 0);
		solve();
		pii ans = pii(0, 0);
		while (m--) 
		{
			scanf("%d", &x);
			ans.xx *= 10;
			if (ans.yy) ans.yy = 0, ans.xx += 5;
			ans.xx += res[x].xx;
			ans.yy += res[x].yy;
			ans.xx %= mod;
		}
		cout << ans.xx;
		if (ans.yy) cout << ".5" << endl;
		else cout << ".0" << endl;
	}
	return 0;
}


你可能感兴趣的:(HDU,数据结构,线段树)