https://www.luogu.com.cn/problem/P4175
第k大先转第k小。
考虑离线。离线完后此题采用整体二分,对于当前二分区间是独立的。把所以操作的查询按时间戳排序。
对于修改操作,如果当前点上的值小于等于mid,则可以有贡献。
对于查询操作,要判断当前两点链上有多少个点有权值。可以用树上差分来解决,所以上一步的维护就要支持子树加,所以转dfs序就是区间加单点求值,树状数组可维护。
如果当前有点的权值数量太多,说明答案小于等于mid,那就丢到左边去二分。如果太少,说明答案大于mid,那么久先减去当前二分区间的贡献, 再丢到右边。
pre coding at 14:26
st coding at 16:21
st bugging at 18:21
passing at 18:51
fn blogging at 19:00
#include<bits/stdc++.h>
using namespace std;
#ifdef LOCALd
#define debug(...) fprintf(stdout, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
//#define int long long
inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||
ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
#define fi first
#define se second
//srand(time(0));
#define N 80010
//#define M
//#define mo
struct node {
int op, x, y, t, k;
};
vector<node>s;
int n, m, i, j, k, T;
int ans[N], f[N][22], L[N], R[N], dfn[N], dep[N];
int tot, q, u, v, a[N], x, y, len;
vector<int>G[N];
void dfs(int x, int fa) {
dep[x]=dep[fa]+1; f[x][0]=fa;
dfn[x]=L[x]=++tot;
for(int y : G[x]) {
if(y == fa) continue;
dfs(y, x);
}
R[x]=tot;
}
int lca(int x, int y) {
if(x==y) return x;
if(dep[x] < dep[y]) swap(x, y);
for(int k=20; k>=0; --k)
if(dep[f[x][k]]>=dep[y]) x=f[x][k];
if(x==y) return x;
for(int k=20; k>=0; --k)
if(f[x][k] != f[y][k]) x=f[x][k], y=f[y][k];
return f[x][0];
}
struct Binary_tree {
int cnt[N];
void add(int x, int k) {
while(x<N) cnt[x]+=k, x+=x&-x;
}
int que(int x) {
int ans=0;
while(x) ans+=cnt[x], x-=x&-x;
return ans;
}
int calc(int x, int y) {
int z = lca(x, y);
// debug("calc(%d %d) => %d | %d %d %d %d\n", x, y, que(dfn[x])+que(dfn[y])-que()-que(f[z][0]), que(dfn[x]), que(dfn[y]), qye(z), );
return que(dfn[x])+que(dfn[y])-que(dfn[z])-que(dfn[f[z][0]]);
}
void add(int l, int r, int k) {
add(l, k); add(r+1, -k);
}
}Bin;
void solve(int l, int r, vector<node>s) {
if(l==r) {
for(auto t : s) if(t.op==2) ans[t.t]=l;
return ;
}
int mid = (l + r) >> 1;
auto cmp = [&] (node x, node y) -> bool {
if(x.t == y.t) return x.op < y.op;
return x.t < y.t;
};
sort(s.begin(), s.end(), cmp);
debug("######$$####### [%d %d] mid %d\n", l, r, mid);
// for(auto t : s) debug("%d(op) %d(x) %d(y) %d(t) %d(k)\n", t.op, t.x, t.y, t.t, t.k);
int x, k;
vector<node>va, vb;
for(auto t : s) {
debug("%d(op) %d(x) %d(y) %d(t) %d(k)\n", t.op, t.x, t.y, t.t, t.k);
if(t.op==1) {
if(t.y <= mid) {
va.pb(t); x=t.x;
debug("Add[%d %d] %d\n", L[x], R[x], x);
Bin.add(L[x], R[x], t.k);
}
else vb.pb(t);
}
else {
k = Bin.calc(t.x, t.y);
if(k >= t.k) va.pb(t);
else t.k-=k, vb.pb(t);
}
}
for(auto t : va) if(t.op==1) Bin.add(L[t.x], R[t.x], -t.k);
if(!va.empty()) solve(l, mid, va);
if(!vb.empty()) solve(mid+1, r, vb);
}
signed main() {
#ifdef LOCALs
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
// T=read();
// while(T--) {
//
// }
n=read(); q=read();
for(i=1; i<=n; ++i) { a[i]=read(); s.pb({1, i, a[i], 1, 1}); }
for(i=1; i<n; ++i) { u=read(); v=read(); G[u].pb(v); G[v].pb(u); }
dfs(1, 0);
for(k=1; k<=20; ++k) for(i=1; i<=n; ++i) f[i][k]=f[f[i][k-1]][k-1];
debug("dep : "); for(i=1; i<=n; ++i) debug("%d ", dep[i]); debug("\n");
for(i=1; i<=q; ++i) {
k=read(); x=read(); y=read();
if(k==0) {
s.pb({1, x, a[x], i, -1});
a[x]=y;
s.pb({1, x, a[x], i, 1});
}
else {
len=dep[x]+dep[y]-2*dep[lca(x, y)]+1;
// debug("Len (%d <-> %d) %d\n", x, y, len);
debug("%d %d | %d\n", x, y, len-k+1);
if(k > len) ans[i] = -1;
else s.pb({2, x, y, i, len-k+1});
}
}
// solve(1, 10, s);
solve(1, 1e8, s);
for(i=1; i<=q; ++i)
if(!ans[i]) continue;
else if(ans[i]==-1) printf("invalid request!\n");
else printf("%d\n", ans[i]);
return 0;
}