题目链接
给一棵树,有点权,每次询问,x到y路径上点点权的第k小是多少?
强制在线,
第k小,肯定会想到主席树。
但是怎么处理呢?
数组中求区间第k小的方法是 把数组的每个前缀建个权值线段树,然后要查询 l~r 区间的值,就用r的权值线段树中的数量减去l - 1中的就好了。也就是T® - T(l - 1)
现在是在树里面。
方法是:根节点到每个点都建个权值线段树。(当然是主席树那样的,)
然后现在知道了根到每个点,怎么求一个路径上的?
当然是 T(x) + T(y) - T(lca(x,y)) - T(fa(lca(x,y)));
这样求个第k大就好了。
然后就是板子题了。。
记得离散化!
lca板子+主席树板子
就完了。。
一定要有前缀的思想!!!
懂得自闭一晚上找不到bug的感觉吗。。。
建树的时候一定不要手贱写个x != 0 才新建点!!! 这错误都能犯我也是很shabi了
代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef unsigned long long ull;
typedef unordered_set<int>::iterator sit;
#define st first
#define sd second
#define mkp make_pair
#define pb push_back
void tempwj(){freopen("P2633_1.in","r",stdin);freopen("P2633_1.out","w",stdout);}
ll gcd(ll a,ll b){return b == 0 ? a : gcd(b,a % b);}
ll qpow(ll a,ll b,ll mod){a %= mod;ll ans = 1;while(b > 0){if(b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;}
struct cmp{bool operator()(const pii & a, const pii & b){return a.second > b.second;}};
int lb(int x){return x & -x;}
//friend bool operator < (Node a,Node b) 重载
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;
const int maxn = 1e6+10;
const int M = 1e6 + 2;
struct Node
{
int l,r,num;
}node[maxn * 40];
int cnt = 0;
int root[maxn];
void build(int l,int r,int& x,int y,int pos,int num)
{
// if(x == 0)
x = ++cnt;
// else
// printf("%d\n",x);
node[x] = node[y];
node[x].num += num;
if(l == r)
return;
int mid = l + r>> 1;
if(pos <= mid)
build(l,mid,node[x].l,node[y].l,pos,num);
else
build(mid + 1, r,node[x].r,node[y].r,pos,num);
}
int query(int l,int r,int x,int y,int t1,int t2,int k)
{
if(l == r)
return l;
int mid = l + r >> 1;
int s = node[node[x].l].num + node[node[y].l].num - node[node[t1].l].num - node[node[t2].l].num;
if(k <= s)
{
return query(l,mid,node[x].l,node[y].l,node[t1].l,node[t2].l,k);
}
else
return query(mid + 1,r,node[x].r,node[y].r,node[t1].r,node[t2].r,k - s);
}
int dp[maxn][25];
int dep[maxn];
int n,m;
int b[maxn];
int a[maxn];
std::vector<int> vv[maxn];
void dfs(int x,int fa,int de)
{
dp[x][0] = fa;
dep[x] = de;
build(1,m,root[x],root[fa],b[x],1);
for(int i = 0; i< vv[x].size(); i ++ )
{
int v = vv[x][i];
if(v == fa)
continue;
dfs(v,x,de + 1);
}
}
void init()
{
for (int i = 1; i <= 19; i ++ )
{
for(int k = 1; k <= n; k ++ )
{
dp[k][i] = dp[dp[k][i - 1]][i - 1];
}
}
}
int getlca(int x,int y)
{
if(dep[x] < dep[y])
swap(x,y);
for (int i = 19; i >= 0; i -- )
{
if(dep[dp[x][i]] >= dep[y])
{
x = dp[x][i];
}
}
if(x == y)
return x;
for(int i= 19; i >= 0; i -- )
{
if(dp[x][i] != dp[y][i])
{
x = dp[x][i];
y = dp[y][i];
}
}
return dp[x][0];
}
std::vector<int> v;
int get_ans(int x,int y,int k)
{
int t1 = getlca(x,y);
int t2 = dp[t1][0];
// printf("%d %d %d %d\n",t1,t2,1,m);
int ans = query(1,m,root[x],root[y],root[t1],root[t2],k);
return ans;
}
int main()
{
// tempwj();
int q;
scanf("%d%d",&n,&q);
for (int i=1 ; i <= n; i ++ )
{
scanf("%d",&a[i]);
v.pb(a[i]);
}
for(int i =1 ; i< n; i ++ )
{
int x,y;
scanf("%d%d",&x,&y);
vv[x].pb(y);
vv[y].pb(x);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
m = v.size();
for(int i = 1; i <= n; i ++ )
{
b[i] = lower_bound(v.begin(),v.end(),a[i]) - v.begin() + 1;
}
dfs(1,0,1);
// printf("%d\n",cnt);
init();
int ans =0 ;
while(q -- )
{
int x,y,k;
scanf("%d%d%d",&x,&y,&k);
// printf("%d\n",ans);
x ^= ans;
// printf("%d %d\n",x,y);
ans = v[get_ans(x,y,k) - 1];
printf("%d\n",ans);
}
}
/*2147468668 1704459667*/