P4315 月下“毛景树”

P4315 月下“毛景树”

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

爬啊爬~爬啊爬毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~ “毛景树”上有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之间树枝上毛毛果个数最多有多少个。

Solution

树剖
注意线段树下推标记时分清楚对子节点标记的影响

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define LL long long
#define REP(i, x, y) for(int i = (x);i <= (y);i++)
using namespace std;
int RD(){
    int out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const int maxn = 100019,INF = 1e9 + 19;
int head[maxn],nume = 1;
struct Node{
    int v,dis,nxt;
    }E[maxn << 3];
void add(int u,int v,int dis){
    E[++nume].nxt = head[u];
    E[nume].v = v;
    E[nume].dis = dis;
    head[u] = nume;
    }
int num;
int size[maxn], wson[maxn], dep[maxn], fa[maxn], val[maxn];
int top[maxn], pos[maxn], ori[maxn], tot;
void dfs1(int u, int F){
    size[u] = 1;
    for(int i = head[u];i;i = E[i].nxt){
        int v = E[i].v;
        if(v == F)continue;
        val[v] = E[i].dis;
        dep[v] = dep[u] + 1;
        fa[v] = u;
        dfs1(v, u);
        size[u] += size[v];
        if(size[v] > size[wson[u]])wson[u] = v;
        }
    }
void dfs2(int u, int TP){
    top[u] = TP;
    pos[u] = ++tot;
    ori[tot] = u;
    if(!wson[u])return ;
    dfs2(wson[u], TP);
    for(int i = head[u];i;i = E[i].nxt){
        int v = E[i].v;
        if(v == fa[u] || v == wson[u])continue;
        dfs2(v, v);
        }
    }
#define lid (id << 1)
#define rid (id << 1) | 1
struct seg_tree{
    int l, r;
    int max;
    int add, set;
    }tree[maxn << 2];
void pushup(int id){tree[id].max = max(tree[lid].max, tree[rid].max);}
void build(int id, int l, int r){
    tree[id].l = l, tree[id].r = r, tree[id].set = -1;
    if(l == r){
        tree[id].max = val[ori[l]];
        return ;
        }
    int mid = (l + r) >> 1;
    build(lid, l, mid), build(rid, mid + 1, r);
    pushup(id);
    }
void pushdown(int id){
    if(tree[id].set != -1){
        int v = tree[id].set;
        tree[lid].max = tree[rid].max = v;
        tree[lid].set = tree[rid].set = v;
        tree[lid].add = tree[rid].add = 0;
        tree[id].add = 0;
        tree[id].set = -1;
        }
    if(tree[id].add != 0){
        int v = tree[id].add;
        tree[lid].max += v;
        tree[rid].max += v;
        if(tree[lid].set != -1)tree[lid].set += v;
        if(tree[rid].set != -1)tree[rid].set += v;
        tree[lid].add += v;
        tree[rid].add += v;
        tree[id].add = 0;
        }
    }
void update(int id, int v, int l, int r, int o){
    pushdown(id);
    if(tree[id].l == l && tree[id].r == r){
        if(o == 1){//1为全改变
            tree[id].max = v;
            tree[id].set = v;
            }
        else{//0为区间加
            tree[id].max += v;
            tree[id].add += v;
            }
        return ;
        }
    int mid = (tree[id].l + tree[id].r) >> 1;
    if(mid < l)update(rid, v, l, r, o);
    else if(mid >= r)update(lid, v, l, r, o);
    else update(lid, v, l, mid, o), update(rid, v, mid + 1, r, o);
    pushup(id);
    }
int query(int id, int l, int r){
    pushdown(id);
    if(tree[id].l == l && tree[id].r == r)return tree[id].max;
    int mid = (tree[id].l + tree[id].r) >> 1;
    if(mid < l)return query(rid, l, r);
    else if(mid >= r)return query(lid, l, r);
    else return max(query(lid, l, mid), query(rid, mid + 1, r));
    }
void uprange(int x, int y, int v, int o){
    while(top[x] != top[y]){
        if(dep[top[x]] < dep[top[y]])swap(x, y);
        update(1, v, pos[top[x]], pos[x], o);
        x = fa[top[x]];
        }
    if(x == y)return ;
    if(dep[x] > dep[y])swap(x, y);
    update(1, v, pos[x] + 1, pos[y], o);
    }
int Q_max(int x, int y){
    int ret = 0;
    while(top[x] != top[y]){
        if(dep[top[x]] < dep[top[y]])swap(x, y);
        ret = max(ret, query(1, pos[top[x]], pos[x]));
        x = fa[top[x]];
        }
    if(x == y)return ret;
    if(dep[x] > dep[y])swap(x, y);
    ret = max(ret, query(1, pos[x] + 1, pos[y]));
    return ret;
    }
struct EDG{int x, y;}I[maxn];
void init(){
    num = RD();
    REP(i, 1, num - 1){
        int u = RD(), v = RD(), dis = RD();
        I[i] = (EDG){u, v};
        add(u, v, dis), add(v, u, dis);
        }
    dep[1] = 1;
    dfs1(1, -1);
    dfs2(1, 1);
    build(1, 1, num);
    }
void solve(){
    char cmd[19];
    while(1){
        scanf("%s", cmd);
        if(cmd[0] == 'S')return ;
        else if(cmd[0] == 'C' && cmd[1] == 'h'){
            int k = RD(), w = RD();
            uprange(I[k].x, I[k].y, w, 1);
            }
        else if(cmd[0] == 'C' && cmd[1] == 'o'){
            int x = RD(), y = RD(), w = RD();
            uprange(x, y, w, 1);
            }
        else if(cmd[0] == 'A'){
            int x = RD(), y = RD(), w = RD();
            uprange(x, y, w, 0);
            }
        else{
            int x = RD(), y = RD();
            printf("%d\n", Q_max(x, y));
            }
        }
    }
int main(){
    init();
    solve();
    return 0;
    }

原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9895580.html

时间: 2024-10-20 06:12:00

P4315 月下“毛景树”的相关文章

【BZOJ1984】月下“毛景树” 树链剖分+线段树

[BZOJ1984]月下"毛景树" Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里.爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的"毛景树"下面,发现树上长着他最爱吃的毛毛果~~~ "毛景树"上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵"毛景树"有着神奇的魔力,他能改变树枝上毛毛果的个数: ?

[BZOJ1984] 月下“毛景树”|树链剖分|线段树

1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1088  Solved: 348[Submit][Status][Discuss] Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里.爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~~ “毛景树”上有N个节点和N-1条树枝,但节点上是没

BZOJ 1984: 月下“毛景树”( 树链剖分 )

水水的树链剖分... 将边上的权值转到深度较大的点上 , 然后要注意这样做之后修改或者查询 u , v 转到同一条重链上时 ( 假设 u 深度小 ) , 不能把 u 的权值算上 , 因为是 u 和它的 fa 的边的权值 , 从 u 到 v 并没有经过这条边 线段树维护 3 个域 set , add , max . ---------------------------------------------------------------------------- #include<cstdio

[luogu4315]月下“毛景树”

[luogu4315]月下"毛景树" luogu 联赛前复习一发树剖.不会告诉你WA了4发 #define ls x<<1,l,mid #define rs x<<1|1,mid+1,r #include<bits/stdc++.h> using namespace std; const int _=1e5+5; int re(){ int x=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){

bzoj1984 月下“毛景树”

Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里.爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~~ “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数: ? Change k w:将第k条树枝上毛毛果的个数改变为w个. ? Cover u v w:将节点u与节点

[BZOJ1984]月下“毛景树”解题报告|树链剖分

Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里.爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~~ “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数: ? Change k w:将第k条树枝上毛毛果的个数改变为w个. ? Cover u v w:将节点u与节点

题解 P4315 【月下“毛景树”】

题目链接:Luogu P4315 线段树 \(+\) 树链剖分 \[\Large\texttt{description}\] 给定一棵\(n\)个节点的树,有\(n - 1\)条边相连,给出\(u_i~v_i~w_i\) 分别表示 \(u_i,v_i\)有一条边,边权是\(w_i\) 有\(3\)种操作以及\(1\)种询问 \(\bullet\) Change k w:将第k条树枝上毛毛果的个数改变为w个 \(\bullet\) Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都

【BZOJ】1984 月下“毛景树”

[算法]树链剖分+线段树 [题解]线段树的区间加值和区间覆盖操作不能同时存在,只能存在一个. 修改:从根节点跑到目标区域路上的标记全部下传,打完标记再上传回根节点(有变动才需要上传). 询问:访问到目标区域路上的标记全部下传. 我写的线段树版本是在打标记的同时便对该点的询问项(最大值)做了对应更改,即可保证访问到该点得到的ms就是该点的答案. 访问某点时如果要询问最大值就直接拿走,如果要还要访问该点的子节点就需要下传. 而修改了某点的值,它的祖先的值就都需要变动,所以一旦修改必须上传至顶. 对于

[luogu]月下“毛景树”:树 剖 好 题

原题 题意: 给一棵树 , 每一条边都有边权 , 支持四种操作 1. 将第k条边权值修改为k 2. 将节点u到v的边权都覆盖为k 3. 将节点u到v的边权都增加k 4. 询问区间边权最大值 显然树剖 边权转点权然后就是树剖裸题了 怎样边权转点权 对于一个点u , 她的父亲是 v 将 u->v 的边权放到 u 上做点权 然后树剖最后的时候这样操作一波 1 if(a == b) 2 return; 3 if(dep[a] > dep[b]) 4 std::swap(a, b); 5 SgCover