P4315 月下“毛景树”

(color{#0066ff}{题目描述})

毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园。 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里。

爬啊爬~爬啊爬毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~ “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的。但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数:

Change k w:将第k条树枝上毛毛果的个数改变为w个。

Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。

Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。 由于毛毛虫很贪,于是他会有如下询问:

Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。

(color{#0066ff}{输入格式})

第一行一个正整数N。

接下来N-1行,每行三个正整数Ui,Vi和Wi,第i+1行描述第i条树枝。表示第i条树枝连接节点Ui和节点Vi,树枝上有Wi个毛毛果。 接下来是操作和询问,以“Stop”结束。

(color{#0066ff}{输出格式})

对于毛毛虫的每个询问操作,输出一个答案。

(color{#0066ff}{输入样例})

4
1 2 8
1 3 7
3 4 9
Max 2 4
Cover 2 4 5
Add 1 4 10
Change 1 16
Max 2 4
Stop

(color{#0066ff}{输出样例})

9
16

(color{#0066ff}{数据范围与提示})

1<=N<=100,000,操作+询问数目不超过100,000。

保证在任意时刻,所有树枝上毛毛果的个数都不会超过10^9个。

(color{#0066ff}{题解})

树剖维护,把边权转成点权

线段树维护一个变成,一个加

变成的时候把add清空

求链的时候,会发现LCA是没用的,所以最后+1,把lca去掉

#include <bits/stdc++.h>

#define LL long long

const int maxn = 1e5 + 10;

LL in() {
    char ch; int x = 0, f = 1;
    while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    return x * f;
}

struct node {
    int to, dis, id;
    node *nxt;
    node(int to = 0, int dis = 0, int id = 0, node *nxt = NULL):to(to), dis(dis), id(id), nxt(nxt) {}
    void *operator new (size_t) {
        static node *S = NULL, *T = NULL;
        return (S == T) && (T = (S = new node[1024]) + 1024), S++;
    }
};
node *head[maxn];

struct sgt {
    int l, r, add, bc, max;
    sgt *ch[2];
    sgt(int l = 0, int r = 0, int add = 0, int bc = -1, int max = 0):l(l), r(r), add(add), bc(bc), max(max) {}
    void *operator new (size_t) {
        static sgt *S = NULL, *T = NULL;
        return (S == T) && (T = (S = new sgt[1024]) + 1024), S++;
    }
    void upd() {max = std::max(ch[0]->max, ch[1]->max);}
    void dwn() {
        if(~bc) {
            ch[0]->max = ch[1]->max = bc;
            ch[0]->bc = ch[1]->bc = bc;
            ch[0]->add = ch[1]->add = 0;
            bc = -1;
        }
        if(add) {
            ch[0]->max += add;
            ch[1]->max += add;
            ch[0]->add += add;
            ch[1]->add += add;
            add = 0;
        }
    }
};
sgt *root;

int dep[maxn], fa[maxn], siz[maxn], dfn[maxn], redfn[maxn], son[maxn], top[maxn], val[maxn], e[maxn];
int n, cnt;

void add(int from, int to, int dis, int id) {
    node *o = new node(to, dis, id, head[from]);
    head[from] = o;
}

char getch() {
    char ch;
    while(!isalpha(ch = getchar()));
    return ch;
}

void dfs1(int x, int f) {
    dep[x] = dep[f] + 1;
    siz[x] = 1;
    fa[x] = f;
    for(node *i = head[x]; i; i = i->nxt) {
        if(i->to == f) continue;
        val[i->to] = i->dis;
        e[i->id] = i->to;
        dfs1(i->to, x);
        siz[x] += siz[i->to];
        if(!son[x] || siz[i->to] > siz[son[x]]) son[x] = i->to;
    }
}

void dfs2(int x, int t) {
    dfn[x] = ++cnt;
    redfn[cnt] = x;
    top[x] = t;
    if(son[x]) dfs2(son[x], t);
    for(node *i = head[x]; i; i = i->nxt)
        if(!dfn[i->to]) dfs2(i->to, i->to);
}

void build(sgt *&o, int l, int r) {
    o = new sgt(l, r, 0, -1, 0);
    if(l == r) return (void)(o->max = val[redfn[l]]);
    int mid = (l + r) >> 1;
    build(o->ch[0], l ,mid);
    build(o->ch[1], mid + 1, r);
    o->upd();
}

void change(sgt *o, int l, int r, int k) {
    if(o->l > r || o->r < l) return;
    if(l <= o->l && o->r <= r) {
        o->max = k;
        o->add = 0;
        o->bc = k;
        return;
    }
    o->dwn();
    change(o->ch[0], l, r, k), change(o->ch[1], l, r, k);
    o->upd();
}

void lazy(sgt *o, int l, int r, int k) {
    if(o->l > r || o->r < l) return;
    if(l <= o->l && o->r <= r) {
        o->max += k;
        o->add += k;
        return;
    }
    o->dwn();
    lazy(o->ch[0], l, r, k), lazy(o->ch[1], l, r, k);
    o->upd();
}

int query(sgt *o, int l, int r) {
    if(o->l > r || o->r < l) return -1;
    if(l <= o->l && o->r <= r) return o->max;
    o->dwn();
    return std::max(query(o->ch[0], l, r), query(o->ch[1], l, r));
}

void changepath(int x, int y, int z) {
    int fx = top[x], fy = top[y];
    while(fx != fy) {
        if(dep[fx] >= dep[fy]) {
            change(root, dfn[fx], dfn[x], z);
            x = fa[fx];
        }
        else {
            change(root, dfn[fy], dfn[y], z);
            y = fa[fy];
        }
        fx = top[x], fy = top[y];
    }
    if(dep[y] < dep[x]) std::swap(x, y);
    change(root, dfn[x] + 1 ,dfn[y], z);
}

void addpath(int x, int y, int z) {
    int fx = top[x], fy = top[y];
    while(fx != fy) {
        if(dep[fx] >= dep[fy]) {
            lazy(root, dfn[fx], dfn[x], z);
            x = fa[fx];
        }
        else {
            lazy(root, dfn[fy], dfn[y], z);
            y = fa[fy];
        }
        fx = top[x], fy = top[y];
    }
    if(dep[y] < dep[x]) std::swap(x, y);
    lazy(root, dfn[x] + 1 ,dfn[y], z);
}

int querymax(int x, int y) {
    int ans = 0;
    int fx = top[x], fy = top[y];
    while(fx != fy) {
        if(dep[fx] >= dep[fy]) {
            ans = std::max(ans, query(root, dfn[fx], dfn[x]));
            x = fa[fx];
        }
        else {
            ans = std::max(ans, query(root, dfn[fy], dfn[y]));
            y = fa[fy];
        }
        fx = top[x], fy = top[y];
    }
    if(dep[y] < dep[x]) std::swap(x, y);
    return std::max(ans, query(root, dfn[x] + 1, dfn[y]));
}

int main() {
    n = in();
    int x, y, z;
    for(int i = 1; i < n; i++) {
        x = in(), y = in(), z = in();
        add(x, y, z, i);
        add(y, x ,z ,i);
    }
    dfs1(1, 0);
    dfs2(1, 1);
    build(root, 1, n);
    while("xu mao zhe shi dalao %%%%%%% ") {
        char ch = getch();
        if(ch == 'S') break;
        if(ch == 'C') {
            if(getch() == 'h') x = in(), y = in(), change(root, dfn[e[x]], dfn[e[x]], y);
            else x = in(), y = in(), z = in(), changepath(x, y, z); 
        }
        if(ch == 'A') x = in(), y = in(), z = in(), addpath(x, y, z); 
        if(ch == 'M') x = in(), y = in(), printf("%d
", querymax(x, y));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/olinr/p/10152254.html