// spoj 10628 Count on a tree
//
// 题目大意:
// 一棵树上,节点有权值.给q个查询,询问u到v路径上第k小的值
//
// 解题思路:
//
// 函数式线段树.首先离散化,将最后不同的元素的个数设为tot记录下来,然后
// 先建立一颗1-tot的空的线段树.按照dfs序列建立函数式线段树.问什么按照dfs序列.
// 因为这样可以将树上节点变成线性结构.我们需要的答案只与四颗树有关即rt[u],
// rt[v],rt[LCA(u,v)],rt[father[LCA(u,v)]].函数式线段树也满足加减性质.所以十分
// 方便.
//
// 感悟:
//
// 这道题搞了好久,是看着大神的代码做的.主要是学习一下函数式线段树.然而我敲出来
// 就是wa.开始瞎bb弄了个LCA-倍增算法的模板一套,一直wa.我还没怀疑LCA错了.最后只差LCA
// 了,我才发现LCA真的错了...然后怒用树链剖分的方式求LCA,结果过了~~~心情还是很激动的呢
// 感觉函数式线段树就是每次对于前面一颗线段树建立一个新的节点保存之前没有修改的节点
// 的信息,而且更省空间.主要作用应该是计数问题,继续加油吧~~~FIGHTING!!!
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#define For(x,a,b,c) for (int x = a; x <= b; x += c)
#define Ffor(x,a,b,c) for (int x = a; x >= b; x -= c)
#define cls(x,a) memset(x,a,sizeof(x))
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-9;
const int MAX_N = 1e5 + 10000;
const int INF = 1e9 + 7;
const ll MOD = 1e9 + 7;
int N,M;
int a[MAX_N];
int b[MAX_N];
vector<int> g[MAX_N];
//int pa[MAX_N][20];
//int dep[MAX_N];
int top[MAX_N];
int idx[MAX_N];
int siz[MAX_N];
int son[MAX_N];
int dep[MAX_N];
int father[MAX_N];
struct node{
int ls;
int rs;
int cnt;
};
int tot;
struct IntervalTree{
node p[MAX_N * 20];
int rt[MAX_N];
int Siz;
void init(){
Siz = 1;
}
int build(int L,int R){
int rt = Siz++;
p[rt].cnt = 0;
if (L == R){
return rt;
}
int M = (L + R) >> 1;
p[rt].ls = build(L,M);
p[rt].rs = build(M+1,R);
return rt;
}
int update(int rt,int L,int R,int q,int v){
int nrt = Siz++;
p[nrt] = p[rt];
p[nrt].cnt += v;
if (L == R){
return nrt;
}
int M = (L + R) >> 1;
if (q <= M)
p[nrt].ls = update(p[rt].ls,L,M,q,v);
else
p[nrt].rs = update(p[rt].rs,M+1,R,q,v);
return nrt;
}
int query(int rtl,int rtr,int rlca,int rf_lca,int L,int R,int k){
if (L == R){
return L;
}
int M = (L + R) >> 1;
int tmp = p[p[rtl].ls].cnt + p[p[rtr].ls].cnt - p[p[rlca].ls].cnt - p[p[rf_lca].ls].cnt;
if (tmp >= k){
return query(p[rtl].ls,p[rtr].ls,p[rlca].ls,p[rf_lca].ls,L,M,k);
}else
return query(p[rtl].rs,p[rtr].rs,p[rlca].rs,p[rf_lca].rs,M+1,R,k - tmp);
}
}it;
void dfs(int u,int fa,int d){
dep[u] = d;
father[u] = fa;
son[u] = 0;
siz[u] = 1;
//pa[u][0] = fa;
For(i,0,g[u].size()-1,1){
int v = g[u][i];
if (v == fa)
continue;
dfs(v,u,d+1);
siz[u] += siz[v];
if (siz[son[u]] < siz[v])
son[u] = v;
}
}
void dfs_2(int u,int tp){
top[u] = tp;
//idx[u] = id++;
if (son[u])
dfs_2(son[u],tp);
For(i,0,g[u].size()-1,1){
int v =g[u][i];
if (v == father[u] || v == son[u])
continue;
dfs_2(v,v);
}
}
int LCA_init(){
dfs(1,0,1);
dfs_2(1,1);
}
int LCA(int u,int v){
int p = top[u];
int q = top[v];
while(p != q){
if (dep[p] < dep[q]){
swap(p,q);
swap(u,v);
}
u = father[p];
p = top[u];
}
if (dep[u] > dep[v])
swap(u,v);
return u;
}
//void LCA_init(){
// cls(pa,-1);
// dfs(1,1,1);
// for (int j = 1;(1<<j) <= N; j++){
// for (int i = 1;i <= N ;i ++){
// pa[i][j] = pa[pa[i][j-1]][j-1];
// }
// }
//}
//
//int LCA(int u,int v){
// int i,j;
//
// if (dep[u] < dep[v])
// swap(u,v);
// for (i = 0;(1<<i) <= dep[u];i++);
//
// i--;
//
// for (j = i; j>= 0;j --)
// if (dep[u] - (1<<j) >= dep[v])
// u = pa[u][j];
//
// if (u == v)
// return u;
//
// for (j = i; j >=0;j --){
// if (pa[u][j]!=-1 && pa[u][j]!=pa[v][j]){
// u = pa[u][j];
// v = pa[v][j];
// }
// }
// return pa[u][0];
//}
void dfs(int u,int fa){
For(i,0,g[u].size()-1,1){
int v =g[u][i];
if (v == fa)
continue;
it.rt[v] = it.update(it.rt[u],1,tot,a[v],1);
//it.rt[v] = it.update(it.rt[u],a[v],1);
dfs(v,u);
}
}
void print(){
For(i,1,N,1)
printf("%d ",a[i]);
cout << endl;
}
void input(){
int m = 0;
For(i,1,N,1){
scanf("%d",&a[i]);
b[i] = a[i];
}
For(i,1,N-1,1){
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
sort(b+1,b+N+1);
tot = unique(b+1,b+N+1) - b - 1;
// b[tot + 1] = INF;
//cout << " ---" << tot << endl;
it.init();
it.rt[0] = it.build(1,tot);
For(i,1,N,1){
a[i] = lower_bound(b,b+tot+1,a[i]) - b;
}
//print();
it.rt[1] = it.update(it.rt[0],1,tot,a[1],1);
//it.rt[1] = it.update(it.rt[0],a[1],1);
dfs(1,-1);
LCA_init();
}
void solve(){
For(i,1,M,1){
int u,v,k;
scanf("%d%d%d",&u,&v,&k);
int t = LCA(u,v);
//printf("%d %d %d %d\n",it.rt[u],it.rt[v],t,k);
printf("%d\n",b[it.query(it.rt[u],it.rt[v],it.rt[t],it.rt[father[t]],1,tot,k)]);
//printf("%d\n",b[it.query(it.rt[u],it.rt[v],t,k)]);
}
}
void init(){
For(i,1,N,1){
g[i].clear();
}
cls(dep,0);
}
int main(){
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
while(scanf("%d%d",&N,&M)!=EOF){
init();
input();
solve();
}
return 0;
}
spoj 10628 Count on a tree
最新推荐文章于 2021-05-21 14:05:49 发布