题目大意
给定一颗
N
个点的树,现在有
Ord=1
:再读入三个整数
u,v,Lim
表示从
u
到
Ord=2
:再读入两个数
u,Val
表示给在
u
这棵子树的所有物品加上权值
N,M,Q≤105
Val≤109
解题思路
一道链剖的裸题!
对于一个点上的物品,它们权值的大小关系是确定的。那么我们只要在一开始把物品都丢到节点
Ai
上,排个序,权值最小的作为这个点的权值。然后对于第一种操作,我们只需依次的拿出
Lim
个点,即每次都查询区间最小值,然后把这个物品从节点处删掉,然后那个节点再找一个剩余节点中权值最小的作为新的权值,因为每个物品只会被删一次所以复杂度是
O(Nlog2N)
的。第二种操作就很简单了,是经典的区间加。
程序
//YxuanwKeith
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 5;
const LL Inf = 1e15 + 7;
struct Node {
LL Val;
int Num;
Node (LL val, int num){Val = val, Num = num;}
Node (){}
};
struct Tree {
LL add;
int Num;
Node Min;
} Tr[MAXN * 4];
vector<int> P[MAXN];
int N, M, Q, time, Bel[MAXN], Size[MAXN], MSon[MAXN], L[MAXN], R[MAXN], Deep[MAXN], Pre[MAXN], Top[MAXN];
int tot, Last[MAXN], Go[MAXN * 2], Next[MAXN * 2];
void Link(int u, int v) {
Next[++ tot] = Last[u], Last[u] = tot, Go[tot] = v;
}
Node Min(Node A, Node B) {
if (A.Val < B.Val) return A;
if (A.Val > B.Val) return B;
if (A.Num < B.Num) return A;
return B;
}
void Basis(int Now, int Fa) {
Size[Now] = 1, MSon[Now] = 0;
Pre[Now] = Fa, Deep[Now] = Deep[Fa] + 1;
for (int p = Last[Now]; p; p = Next[p]) {
int v = Go[p];
if (v == Fa) continue;
Basis(v, Now);
Size[Now] += Size[v];
if (Size[v] > Size[MSon[Now]]) MSon[Now] = v;
}
}
void Promote(int Now, int top) {
if (!Now) return;
L[Now] = ++ time, Bel[time] = Now;
Top[Now] = top;
Promote(MSon[Now], top);
for (int p = Last[Now]; p; p = Next[p]) {
int v = Go[p];
if (v == Pre[Now] || v == MSon[Now]) continue;
Promote(v, v);
}
R[Now] = time;
}
bool Cmp(int A, int B) {
return A > B;
}
Node Get(int Now) {
if (P[Now].empty()) return Node(Inf, Bel[Now]);
return Node(P[Now].back(), Bel[Now]);
}
Node Up(Node A, LL add) {
A.Val += add;
return A;
}
void MakeTag(int Now, LL add) {
Tr[Now].add += add;
}
void Push(int Now, int l, int r) {
if (l != r) {
int Mid = (l + r) >> 1;
MakeTag(Now * 2, Tr[Now].add);
MakeTag(Now * 2 + 1, Tr[Now].add);
Tr[Now].Min = Min(Up(Tr[Now * 2].Min, Tr[Now * 2].add), Up(Tr[Now * 2 + 1].Min, Tr[Now * 2 + 1].add));
Tr[Now].add = 0;
}
}
void Modify(int Now, int l, int r, int lx, int rx, LL add) {
Push(Now, l, r);
if (l == lx && r == rx) {
MakeTag(Now, add);
return;
}
int Mid = (l + r) >> 1;
if (rx <= Mid) Modify(Now * 2, l, Mid, lx, rx, add); else
if (lx > Mid) Modify(Now * 2 + 1, Mid + 1, r, lx, rx, add); else {
Modify(Now * 2, l, Mid, lx, Mid, add);
Modify(Now * 2 + 1, Mid + 1, r, Mid + 1, rx, add);
}
Tr[Now].Min = Min(Up(Tr[Now * 2].Min, Tr[Now * 2].add), Up(Tr[Now * 2 + 1].Min, Tr[Now * 2 + 1].add));
}
void Build(int Now, int l, int r) {
if (l == r) {
Tr[Now].Min = Get(l);
return;
}
int Mid = (l + r) >> 1;
Build(Now * 2, l, Mid), Build(Now * 2 + 1, Mid + 1, r);
Tr[Now].Min = Min(Tr[Now * 2].Min, Tr[Now * 2 + 1].Min);
}
Node Ask(int Now, int l, int r, int lx, int rx) {
Push(Now, l, r);
if (l == lx && r == rx) return Up(Tr[Now].Min, Tr[Now].add);
int Mid = (l + r) >> 1;
if (rx <= Mid) return Up(Ask(Now * 2, l, Mid, lx, rx), Tr[Now].add); else
if (lx > Mid) return Up(Ask(Now * 2 + 1, Mid + 1, r, lx, rx), Tr[Now].add); else
return Up(Min(Ask(Now * 2, l, Mid, lx, Mid), Ask(Now * 2 + 1, Mid + 1, r, Mid + 1, rx)), Tr[Now].add);
}
int Ask(int u, int v) {
Node Ans = Node(Inf, 0);
while (Top[u] != Top[v]) {
if (Deep[Top[u]] < Deep[Top[v]]) swap(u, v);
Ans = Min(Ans, Ask(1, 1, N, L[Top[u]], L[u]));
u = Pre[Top[u]];
}
if (L[u] > L[v]) swap(u, v);
Ans = Min(Ans, Ask(1, 1, N, L[u], L[v]));
return Ans.Num;
}
void Del(int Now, int l, int r, int Side) {
Push(Now, l, r);
if (l == r) {
P[l].pop_back();
Tr[Now].Min = Get(l);
return;
}
int Mid = (l + r) >> 1;
if (Side <= Mid) Del(Now * 2, l, Mid, Side); else
Del(Now * 2 + 1, Mid + 1, r, Side);
Tr[Now].Min = Min(Up(Tr[Now * 2].Min,Tr[Now * 2].add), Up(Tr[Now * 2 + 1].Min, Tr[Now * 2 + 1].add));
}
void Query(int u, int v, int Lim) {
static int D[MAXN];
int top = 0;
for (int i = 1; i <= Lim; i ++) {
int Now = L[Ask(u, v)];
if (!Now) break;
D[++ top] = P[Now].back();
Del(1, 1, N, Now);
}
printf("%d ", top);
for (int i = 1; i <= top; i ++) printf("%d ", D[i]);
printf("\n");
}
void Prepare() {
Basis(1, 0);
Promote(1, 1);
}
int main() {
scanf("%d%d%d", &N, &M, &Q);
for (int i = 1; i < N; i ++) {
int u, v;
scanf("%d%d", &u, &v);
Link(u, v), Link(v, u);
}
Prepare();
for (int i = 1; i <= M; i ++) {
int Val;
scanf("%d", &Val);
P[L[Val]].push_back(i);
}
for (int i = 1; i <= N; i ++) sort(P[i].begin(), P[i].end(), Cmp);
Build(1, 1, N);
for (int i = 1; i <= Q; i ++) {
int Ord;
scanf("%d", &Ord);
if (Ord == 1) {
int u, v, Lim;
scanf("%d%d%d", &u, &v, &Lim);
Query(u, v, Lim);
} else {
int u, add;
scanf("%d%d", &u, &add);
Modify(1, 1, N, L[u], R[u], add);
}
}
}