数据结构题总是很令人开心的。


这题据说可以主席树?好麻烦的说。


树链剖分+线段树+treap就好了吧。


#include <cstdio>

#include <cstdlib>

#include <cctype>

#include <memory.h>

#include <algorithm>


using namespace std;


struct edge {

int t;

edge *next;

};

struct seg {

int l, r, v;

seg *ls, *rs;

};


#define readInt(_s_) {\

int _d_;\

_s_ = 0;\

while (!isdigit(_d_ = getchar()));\

while ((_s_ = _s_ * 10 + _d_ - 48), isdigit(_d_ = getchar()));\

}


const int maxn = 80009;

const int maxv = 1e8;


namespace treap {

struct node {

int ls, rs, v, w, sz;

};

const int maxnd = 80009 * 19;

node a[maxnd];

int tn, nst[maxnd];

void init() {

srand(239407234);

a[0]. sz = 0;

tn = 0;

for (int i = 1; i < maxnd; ++ i)

nst[++ tn] = i;

}

inline int newNode(int v) {

int p = nst[tn --];

a[p]. ls = 0;

a[p]. rs = 0;

a[p]. v = v;

a[p]. w = rand() | (rand() << 16);

a[p]. sz = 1;

return p;

}

inline void update(const int& p) {

a[p]. sz = a[a[p]. ls]. sz + a[a[p]. rs]. sz + 1;

}

inline void lRot(int& p) {

int q = a[p]. rs;

a[p]. rs = a[q]. ls;

a[q]. ls = p;

update(p);

update(q);

p = q;

}

inline void rRot(int& p) {

int q = a[p]. ls;

a[p]. ls = a[q]. rs;

a[q]. rs = p;

update(p);

update(q);

p = q;

}

inline void maintain(int& p, bool d) {

if (d) {

if (a[a[p]. ls]. w > a[p]. w)

rRot(p);

}

else

if (a[a[p]. rs]. w > a[p]. w)

lRot(p);

}

inline void ins(int& p, int v) {

if (!p)

p = newNode(v);

else {

if (v < a[p]. v)

ins(a[p]. ls, v);

else

ins(a[p]. rs, v);

update(p);

maintain(p, v < a[p]. v);

}

}

inline void ers(int& p, int v) {

if (!p)

return;

else if (a[p]. v == v) {

if (!a[p]. ls)

p = a[p]. rs;

else if (!a[p]. rs)

p = a[p]. ls;

else {

int q = a[p]. ls;

while (a[q]. rs)

q = a[q]. rs;

a[p]. v = a[q]. v;

ers(a[p]. ls, a[p]. v);

update(p);

}

}

else {

if (v < a[p]. v)

ers(a[p]. ls, v);

else

ers(a[p]. rs, v);

update(p);

}

}

inline int cnt(int p, int v) {

if (!p)

return 0;

else if (v <= a[p]. v)

return cnt(a[p]. ls, v);

else

return a[a[p]. ls]. sz + 1 + cnt(a[p]. rs, v);

}

};


int n, q, v[maxn];

int tc, d[maxn], fa[maxn], sz[maxn], ch[maxn], fc[maxn], cl[maxn];

seg *rt[maxn], *sp;

edge *ep, *head[maxn];


inline void addEdge(int u, int v) {

ep-> t = v;

ep-> next = head[u];

head[u] = ep ++;

}


#define mid(p) ((p->l+p->r)>>1)


inline seg* sgtBuild(int l, int r) {

seg* p = sp ++;

p-> l = l;

p-> r = r;

p-> v = 0;

if (l + 1 < r) {

p-> ls = sgtBuild(l, mid(p));

p-> rs = sgtBuild(mid(p), r);

}

return p;

}


inline void sgtChg(seg* p, int p0, int v, int ty) {

if (ty == 1)

treap :: ins(p-> v, v);

else

treap :: ers(p-> v, v);

if (p-> l + 1 == p-> r)

return;

else if (p0 < mid(p))

sgtChg(p-> ls, p0, v, ty);

else

sgtChg(p-> rs, p0, v, ty);

}


inline int sgtQry(seg* p, int l, int r, int v) {

if (l >= r)

return 0;

else if (p-> l == l && p-> r == r)

return treap :: cnt(p-> v, v);

else if (r <= mid(p))

return sgtQry(p-> ls, l, r, v);

else if (l >= mid(p))

return sgtQry(p-> rs, l, r, v);

else

return sgtQry(p-> ls, l, mid(p), v) + sgtQry(p-> rs, mid(p), r, v);

}


#define cpos(_p_) (d[_p_]-d[ch[fc[_p_]]])


void divide() {

static int q[maxn];

int hd = 0, tl = 1;

memset(d, 0, sizeof(d));

d[1] = 1;

fa[1] = 0;

q[0] = 1;

while (hd < tl) {

int p = q[hd ++];

for (edge* e = head[p]; e; e = e-> next)

if (!d[e-> t]) {

d[e-> t] = d[p] + 1;

fa[e-> t] = p;

q[tl ++] = e-> t;

}

}

tc = 0;

for (int ti = tl - 1; ti >= 0; -- ti) {

int p = q[ti], x = -1;

sz[p] = 1;

for (edge* e = head[p]; e; e = e-> next)

if (fa[e-> t] == p) {

sz[p] += sz[e-> t];

if (x == -1 || sz[e-> t] > sz[x])

x = e-> t;

}

if (x == -1) {

fc[p] = ++ tc;

ch[fc[p]] = p;

cl[fc[p]] = 1;

}

else {

fc[p] = fc[x];

ch[fc[p]] = p;

++ cl[fc[p]];

}

}

sp = new seg[maxn * 4];

for (int i = 1; i <= tc; ++ i)

rt[i] = sgtBuild(0, cl[i]);

for (int i = 1; i <= n; ++ i)

sgtChg(rt[fc[i]], cpos(i), v[i], 1);

}


int LCA(int u, int v) {

while (fc[u] ^ fc[v])

if (d[ch[fc[u]]] > d[ch[fc[v]]])

u = fa[ch[fc[u]]];

else

v = fa[ch[fc[v]]];

if (d[u] < d[v])

return u;

else

return v;

}


int cntChain(int u, int a, int v) {

int s = 0;

while (fc[u] ^ fc[a]) {

s += sgtQry(rt[fc[u]], 0, cpos(u) + 1, v);

u = fa[ch[fc[u]]];

}

if (u ^ a)

s += sgtQry(rt[fc[u]], cpos(a) + 1, cpos(u) + 1, v);

return s;

}


int main() {

#ifndef ONLINE_JUDGE

freopen("in.txt", "r", stdin);

#endif


treap :: init();

memset(head, 0, sizeof(head));

ep = new edge[maxn * 2];

readInt(n);

readInt(q);

for (int i = 1; i <= n; ++ i)

readInt(v[i]);

for (int i = 0; i < n - 1; ++ i) {

int u, v;

readInt(u);

readInt(v);

addEdge(u, v);

addEdge(v, u);

}

divide();

while (q --) {

int k, a, b;

readInt(k);

readInt(a);

readInt(b);

if (!k) {

sgtChg(rt[fc[a]], cpos(a), v[a], -1);

v[a] = b;

sgtChg(rt[fc[a]], cpos(a), v[a], 1);

}

else {

int l = 0, r = maxv, c = LCA(a, b);

if (d[a] + d[b] - d[c] * 2 + 1 < k)

puts("invalid request!");

else {

k = d[a] + d[b] - d[c] * 2 + 2 - k;

while (l < r) {

int mid = (l + r + 1) >> 1;

if (cntChain(a, c, mid) + cntChain(b, fa[c], mid) >= k)

r = mid - 1;

else

l = mid;

}

printf("%d\n", l);

}

}

}

}