CF 696E ...Wait for it... 链剖练手题

来源:互联网 发布:乐清市知临学校招聘 编辑:程序博客网 时间:2024/05/23 17:13

题目大意

给定一颗N个点的树,现在有M个物品,每个物品一开始都在节点Ai上,权值为i。现在有两种操作,先读入Ord
Ord=1:再读入三个整数u,v,Lim表示从uv这条路径上从小到大把最多Lim个物品从树上取出,并且从小到大输出。
Ord=2:再读入两个数u,Val表示给在u这棵子树的所有物品加上权值Val

N,M,Q105
Val109

解题思路

一道链剖的裸题!
对于一个点上的物品,它们权值的大小关系是确定的。那么我们只要在一开始把物品都丢到节点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);        }    }}
1 0