Codeforces 587C Duff in the Army

题意:给出一棵树,每个节点有一个权值集合(一个点有多个值),现在有q个询问,query(u,v,a)表示询问u到v之间的前a小的数。

与 http://blog.csdn.net/mr_xujh/article/details/47271843 差不多

就是这一题的每个节点上有多个值,不用离散化,查询的时候要输出前a小

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 200010;
const int M = N * 40;
int n,m,q,tot;
int a[N],t[N];
int T[N],ls[M],rs[M],c[M],d[N],fa[N][27];
vector<int> vec[N],peo[N],ans;
void init(){
    memset(fa, -1, sizeof(fa));
    tot = 0;
}
void build(int l, int r, int &rt){
	rt = tot ++;
	c[rt] = 0;
	if(l != r){
		int mid = (l+r)>>1;
		build(l, mid, ls[rt] );
		build(mid+1, r, rs[rt]);
	}
}
int update(int root, int pos, int val){
	int newroot = tot++, tmp = newroot;
	c[newroot] = c[root] + val;
	int l = 1, r = m;
	while(l < r){
		int mid = (l+r)>>1;
		if(pos <= mid){
			ls[newroot] = tot++;
			rs[newroot] = rs[root];
			newroot = ls[newroot];
			root = ls[root];
			r = mid;
		}
		else {
			rs[newroot] = tot++;
			ls[newroot] = ls[root];
			newroot = rs[newroot];
			root = rs[root];
			l = mid+1;
		}
		c[newroot] = c[root] + val;
	}
	return tmp;
}
int query(int lrt, int rrt, int lca, int k){
	int lcart = T[lca], fart = T[fa[lca][0]];
	int l = 1, r = m;
	int cot = c[lrt] + c[rrt] - c[lcart] - c[fart];
	if(cot<k)return -1;
	while(l < r){
		int mid = (l+r)>>1;
		cot = c[ls[lrt]] + c[ls[rrt]] - c[ls[lcart]] - c[ls[fart]];
		if(cot >= k){
			r = mid;
			lrt = ls[lrt];
			rrt = ls[rrt];
			lcart = ls[lcart];
			fart = ls[fart];
		}
		else {
			l = mid+1;
			k -= cot;
			lrt = rs[lrt];
			rrt = rs[rrt];
			lcart = rs[lcart];
			fart = rs[fart];
		}
	}
	return l;
}
void dfs_build(int u, int pre){
	fa[u][0] = pre;
	d[u] = d[pre] + 1;
	int sz = peo[u].size();
	T[u] = T[pre];
	for(int i = 0; i < sz; i++){
        T[u] = update(T[u], peo[u][i], 1);
	}
	//cout<<"ok"<<endl;
    sz = vec[u].size();
    for(int i = 0; i < sz; i++){
        int v = vec[u][i];
        if(v != pre){
            dfs_build(v, u);
        }
    }
}
void init_fa(){
    for(int j = 1; (1<<j) <= n; j++){
        for(int i = 1; i <= n; i++){
            fa[i][j] = fa[fa[i][j-1]][j-1];
        }
    }
}
int LCA(int a, int b){
    int i, j;
    if(d[a] < d[b])swap(a, b);
    for(i = 0; (1<<i) <= d[a]; i++);i--;
    for( j = i; j >= 0; j--){
        if(d[a] - (1<<j) >= d[b])
            a = fa[a][j];
    }
    if(a == b)return a;
    for(j = i; j >= 0; j--){
        if(fa[a][j] != -1 && fa[a][j] != fa[b][j]){
            a = fa[a][j], b = fa[b][j];
        }
    }
    return fa[a][0];
}

int main(){
	int u,v,k;
    //freopen("in.txt","r",stdin);
	while(~scanf("%d%d%d", &n, &m, &q)){
		init();
		for(int i = 1; i < n; i++){
			scanf("%d%d", &u, &v);
			vec[u].push_back(v);
			vec[v].push_back(u);
		}
		for(int i = 1; i <= m ; i++ ){
            scanf("%d", &u);
            peo[u].push_back(i);
        }
		build(1, m, T[0]);
		dfs_build(1, 0);
		init_fa();
		while(q--){
            ans.clear();
			scanf("%d%d%d", &u, &v, &k);
			int lca = LCA(u, v);
			//cout<<lca<<endl;
			for(int i = 1; i <= k; i++){
                int tmp = query(T[u],T[v],lca,i);
                if(tmp>0)ans.push_back(tmp);
                else break;
			}
			int sz = ans.size();
            printf("%d", sz);
            for(int j = 0; j < sz; j++) printf(" %d", ans[j]);
            puts("");
		}
		for(int i = 1; i <= n; i++){vec[i].clear(),peo[i].clear();}
	}
	return 0;
}



你可能感兴趣的:(codeforces,主席树)