【题目大意】
给定一颗点上带权的树,每次可以修改某点的权值,或者询问两点u,v树上唯一路径的第k大权值。
【分析】
这类树上路径问题直接轻重权树链剖分就好啦。。
但是是询问第k大,所以我们用一个树状数组套Trie树维护区间权值即可
。。
注意用BFS来剖分避免爆栈
【代码】
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <deque>
#include <vector>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define rrep(i,b,a) for(int i=(b);i>=(a);--i)
#define MAXN 80010
#define lowbit(x) ((x)&(-(x)))
#define sf scanf
#define pf printf
#define p_b push_back
#define p_f push_front
#define pp_f pop_front
string error("invalid request!");
struct edge{
int v;
edge* next;
}*head[MAXN],Edge[MAXN<<1];
struct TrieNode{
#define node TrieNode
node* ch[2];
int sz;
}*root[MAXN],pool[MAXN*200],*New=pool;
int N,Q;
int tid[MAXN],top[MAXN];
int size[MAXN],son[MAXN];
int fa[MAXN],dep[MAXN];
int val[MAXN];
int totEdge;
void Addedge(int u,int v){
Edge[totEdge].v=v;
Edge[totEdge].next=head[u];
head[u]=&Edge[totEdge++];
}
node* Get(){
New->ch[0]=New->ch[1]=NULL;
New->sz=0;
return New++;
}
void Read(int& x){
char tt=getchar();
while(tt<'0'||'9'<tt) tt=getchar();
for(x=0;'0'<=tt&&tt<='9';x=(x<<1)+(x<<3)+tt-'0',tt=getchar());
}
void Find_heavy_edge(int root){
queue <int> Q;
vector <int> Ts;
Q.push(root);
Ts.p_b(root);
while(!Q.empty()){
int u=Q.front();
Q.pop();
size[u]=1;
dep[u]=dep[fa[u]]+1;
for(edge* p=head[u];p!=NULL;p=p->next)
if(p->v!=fa[u]){
fa[p->v]=u;
Q.push(p->v);
Ts.p_b(p->v);
}
}
int n=Ts.size();
rrep(i,n-1,0){
int v=Ts[i];
int u=fa[v];
size[u]+=size[v];
if(size[v]>size[son[u]])
son[u]=v;
}
}
void Connect(int root){
int label=0;
deque <int> Q;
Q.p_b(root);
top[root]=root;
while(!Q.empty()){
int u=Q.front();
Q.pp_f();
tid[u]=++label;
if(son[u]){
Q.p_f(son[u]);
top[son[u]]=top[u];
}
for(edge* p=head[u];p!=NULL;p=p->next)
if(p->v!=fa[u]&&p->v!=son[u]){
top[p->v]=p->v;
Q.p_b(p->v);
}
}
}
void Init(){
int u,v;
Read(N);
Read(Q);
rep(i,1,N) Read(val[i]);
rep(i,1,N-1){
Read(u);
Read(v);
Addedge(u,v);
Addedge(v,u);
}
}
void Insert(node* T,int key){
rrep(i,30,0){
T->sz++;
int t=(key>>i)&1;
if(!T->ch[t]) T->ch[t]=Get();
T=T->ch[t];
}
T->sz++;
}
void Delete(node* T,int key){
rrep(i,30,0){
T->sz--;
int t=(key>>i)&1;
T=T->ch[t];
}
T->sz--;
}
void Select(int u,int v,int k){
vector <node*> Plus;
vector <node*> Sub;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])
swap(u,v);
int l=tid[top[u]];
int r=tid[u];
for(int j=r;j;j-=lowbit(j))
Plus.p_b(root[j]);
for(int j=l-1;j;j-=lowbit(j))
Sub.p_b(root[j]);
u=fa[top[u]];
}
if(dep[u]>dep[v])
swap(u,v);
int l=tid[u];
int r=tid[v];
for(int j=r;j;j-=lowbit(j))
Plus.p_b(root[j]);
for(int j=l-1;j;j-=lowbit(j))
Sub.p_b(root[j]);
int n=Plus.size();
int m=Sub.size();
int ans=0;
int t=0;
rep(i,0,n-1) t+=Plus[i]->sz;
rep(i,0,m-1) t-=Sub[i]->sz;
if(t<k){
cout<<error<<endl;
return;
}
rrep(i,30,0){
t=0;
rep(j,0,n-1)
if(Plus[j]&&Plus[j]->ch[1])
t+=Plus[j]->ch[1]->sz;
rep(j,0,m-1)
if(Sub[j]&&Sub[j]->ch[1])
t-=Sub[j]->ch[1]->sz;
if(k<=t){
ans+=(1<<i);
rep(j,0,n-1) if(Plus[j]) Plus[j]=Plus[j]->ch[1];
rep(j,0,m-1) if(Sub[j]) Sub[j]=Sub[j]->ch[1];
}
else{
k-=t;
rep(j,0,n-1) if(Plus[j]) Plus[j]=Plus[j]->ch[0];
rep(j,0,m-1) if(Sub[j]) Sub[j]=Sub[j]->ch[0];
}
}
pf("%d\n",ans);
}
void Solve(){
Find_heavy_edge(1);
Connect(1);
rep(i,1,N){
int p=tid[i];
for(int j=p;j<=N;j+=lowbit(j)){
if(!root[j]) root[j]=Get();
Insert(root[j],val[i]);
}
}
int k,u,v;
while(Q--){
Read(k);
Read(u);
Read(v);
if(!k){
int p=tid[u];
for(int j=p;j<=N;j+=lowbit(j)){
Delete(root[j],val[u]);
Insert(root[j],v);
}
val[u]=v;
}
else Select(u,v,k);
}
}
int main(){
Init();
Solve();
return 0;
}