http://www.lydsy.com/JudgeOnline/problem.php?id=1146
树巨结垢限时训练系列。
选择了 二分 树剖 线段树 Treap 的写法。
1小时写完 15分钟调好…..
感觉写的已经比较漂亮了,可以作为树上单点修改 K 大的一份模版
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
#define rep(i, x, y) for (int i = (x), _ = (y); i <= _; ++i)
#define down(i, x, y) for (int i = (x), _ = (y); i >= _; --i)
#define x first
#define y second
#define LX_JUDGE
using namespace std;
typedef long long LL;
template<typename T> inline void up_max(T & x, T y) { x < y ? x = y : 0; }
template<typename T> inline void up_min(T & x, T y) { x > y ? x = y : 0; }
template<typename T>
inline void read(T & x)
{
char c;
while ((c = getchar()) < '0' || c > '9') ;
for (x = c - '0'; (c = getchar()) >= '0' && c <= '9'; x = x * 10 + c - '0') ;
}
const int N = 8e4 + 10;
namespace Treap
{
struct node
{
node * ch[2];
int val, size, r;
inline void push_up()
{
size = (ch[0] ? ch[0]->size : 0) + (ch[1] ? ch[1]->size : 0) + 1;
}
} pool_node[N * 20], *pool_top = pool_node;
node * root = 0;
void rotate(node *&o, int d)
{
node * u = o->ch[d];
o->ch[d] = u->ch[d ^ 1];
u->ch[d ^ 1] = o;
o->push_up();
u->push_up();
o = u;
}
void insert(node *& o, node * u)
{
if (!o)
{
o = u;
o->ch[0] = o->ch[1] = 0;
o->size = 1;
return ;
}
int d = o->val < u->val;
++o->size;
insert(o->ch[d], u);
if (o->ch[d]->r > o->r)
rotate(o, d);
}
node * recent;
void remove(node *& o, int val)
{
if (o->val == val)
{
if (!o->ch[0])
{
recent = o;
o = o->ch[1];
}
else if (!o->ch[1])
{
recent = o;
o = o->ch[0];
}
else
{
int d = o->ch[1]->r > o->ch[0]->r;
rotate(o, d);
--o->size;
remove(o->ch[d ^ 1], val);
}
}
else
{
int d = o->val < val;
--o->size;
remove(o->ch[d], val);
}
}
void modify(node *& R, int val, int to)
{
remove(R, val);
recent->val = to;
insert(R, recent);
}
node * build(int * a, int n)
{
static node * stk[N];
static int top = 0;
rep(i, 0, n - 1)
{
node * o = ++pool_top, *last = 0;
o->val = a[i];
o->r = rand();
while (top && stk[top]->r < o->r)
stk[top]->push_up(), last = stk[top--];
if (top)
stk[top]->ch[1] = o;
o->ch[0] = last;
stk[++top] = o;
}
while (top)
stk[top--]->push_up();
return stk[1];
}
int getRank(node *o, int val)
{
int ret = 0;
while (o)
{
int d = o->val < val;
if (!d)
ret += (o->ch[1] ? o->ch[1]->size : 0) + 1;
o = o->ch[d];
}
return ret;
}
int query(const vector<node * > & q, int K)
{
int l = 1, r = 1e8;
while (l <= r)
{
int mid = (l + r) >> 1, tmp = 0;
rep (i, 0, q.size() - 1)
tmp += getRank(q[i], mid);
tmp >= K ? l = mid + 1 : r = mid - 1;
}
return r;
}
}
int mem_tmp[N], mem[N];
namespace SegmentTree
{
struct node
{
node * ch[2];
int l, r;
Treap::node * root;
};
node * newnode()
{
static node pool_node[N * 2], * pool_top = pool_node;
return ++pool_top;
}
void build(node *&o, int l, int r)
{
o = newnode();
o->l = l, o->r = r;
if (l == r)
{
o->root = Treap::build(mem + l, 1);
return ;
}
int mid = (l + r) >> 1;
build(o->ch[0], l, mid);
build(o->ch[1], mid + 1, r);
int tl = l, tr = mid + 1;
for (int i = l; i <= r; ++i)
{
if (tr > r || (tl <= mid && mem[tl] < mem[tr]))
mem_tmp[i] = mem[tl++];
else
mem_tmp[i] = mem[tr++];
}
memcpy(mem + l, mem_tmp + l, sizeof(int) * (r - l + 1));
o->root = Treap::build(mem + l, r - l + 1);
}
void split(node *o, int l, int r, vector<Treap::node * > & q)
{
if (l <= o->l && o->r <= r)
{
q.push_back(o->root);
return ;
}
int mid = (o->l + o->r) >> 1;
if (mid >= r)
split(o->ch[0], l, r, q);
else if (mid < l)
split(o->ch[1], l, r, q);
else
split(o->ch[0], l, r, q), split(o->ch[1], l, r, q);
}
int modify(node *o, int pos, int val)
{
if (o->l == o->r)
{
int ret = o->root->val;
Treap::modify(o->root, ret, val);
return ret;
}
int ret = modify(o->ch[((o->l + o->r) >> 1) < pos], pos, val);
Treap::modify(o->root, ret, val);
return ret;
}
}
SegmentTree::node * H[N];
struct edge
{
int to;
edge *n;
} pool_edge[N * 2], *head[N], *cur = pool_edge;
inline void addEdge(int x, int y)
{
cur->to = y, cur->n = head[x], head[x] = cur++;
cur->to = x, cur->n = head[y], head[y] = cur++;
}
struct treenode
{
int size, Hson, deep, fa, top, dfn;
}t[N];
void init_dfs(int x)
{
t[x].size = 1;
for (edge *p = head[x]; p; p = p->n)
{
int to = p->to;
if (t[x].fa == to)
continue ;
t[to].fa = x;
t[to].deep = t[x].deep + 1;
init_dfs(to);
t[x].size += t[to].size;
if (t[to].size > t[t[x].Hson].size)
t[x].Hson = to;
}
}
int ival[N], tim;
void calc_dfs(int x, int tt)
{
t[x].dfn = ++tim;
t[x].top = tt;
mem[tim] = ival[x];
if (t[x].Hson)
{
calc_dfs(t[x].Hson, tt);
for (edge *p = head[x]; p; p = p->n) if (t[x].fa != p->to && t[x].Hson != p->to)
calc_dfs(p->to, p->to);
}
else
SegmentTree::build(H[t[x].top], t[t[x].top].dfn, t[x].dfn);
}
int solve(int x, int y, int K)
{
using SegmentTree::split;
static vector<Treap::node *> Q;
Q.clear();
int cnt = 0;
while (t[x].top != t[y].top)
{
if (t[t[x].top].deep < t[t[y].top].deep)
swap(x, y);
split(H[t[x].top], t[t[x].top].dfn, t[x].dfn, Q);
cnt += t[x].dfn - t[t[x].top].dfn + 1;
x = t[t[x].top].fa;
}
if (t[x].deep > t[y].deep)
swap(x, y);
cnt += t[y].dfn - t[x].dfn + 1;
split(H[t[x].top], t[x].dfn, t[y].dfn, Q);
return cnt >= K ? Treap::query(Q, K) : -1;
}
int main()
{
#ifdef LX_JUDGE
freopen("in.txt", "r", stdin);
#endif
int n, m;
read(n), read(m);
rep (i, 1, n)
read(ival[i]);
for (int i = 1, x, y; i < n; ++i)
{
read(x), read(y);
addEdge(x, y);
}
init_dfs(1);
calc_dfs(1, 1);
int opt, x, y;
while (m--)
{
read(opt);
read(x), read(y);
if (opt == 0)
SegmentTree::modify(H[t[x].top], t[x].dfn, y);
else
{
x = solve(x, y, opt);
x > 0 ? printf("%d\n", x) : puts("invalid request!");
}
}
return 0;
}