[LGOJ4315]月下毛景树——[树链剖分]

【题目描述】

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

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

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

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

S a m p l e    I n p u t Sample\;Input SampleInput

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

S a m p l e    O u t p u t Sample\;Output SampleOutput

9
16

【题意分析】
很久之前就想水这道题了,由于畏惧码量一直没写~~
码量跟国集的那道旅游有的一拼。。。200+行(跟奆佬们的Toptree和RBT比起来少得多了,但对于我这种蒟蒻还是写了1h+)

思路就是边权树剖,维护一颗区间最大值的线段树,有两个懒标记lazyA[],lazyC[]分别代表区间加懒标记、区间覆盖懒标记~~
p u s h d o w n pushdown pushdown时,区间覆盖标记优先处理。

代码很多地方都是基本一样的,太无脑了。。。
真水

Code:

#pragma GCC optimize(2)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<cstring>
#include<vector>
#include<algorithm>
#define Read(a) a = read <int> () 
#define MAXN 200000
#define int long long
#define INF 1 << 30
using namespace std;

int tree[MAXN << 2],lazyA[MAXN << 2],lazyC[MAXN << 2],father[MAXN],son[MAXN];
int head[MAXN << 1],top[MAXN],id[MAXN],value[MAXN],rk[MAXN],depth[MAXN],size[MAXN];
int n,cnt,dfn,res,ans;

struct Front_Link_Star{
    int from,to,next,v;
}edge[MAXN << 1];

//连边,记录从哪里来,到哪里去(这是为了边权化点权)
inline void connect (int u,int v,int w){
    edge[++cnt].from = u;
    edge[cnt].to = v;
    edge[cnt].v = w;
    edge[cnt].next = head[u];
    head[u] = cnt;
}

template <typename T> inline T read (){
    register int s = 0,w = 1;
    register char ch = getchar ();
    while (!isdigit (ch)){if (ch == '-')w = -1;ch = getchar ();}
    while (isdigit (ch)){s = (s << 3) + (s << 1) + ch - '0';ch = getchar ();}
    return s*w;
}

//判断权值应该给谁(深度大的那个)
inline void which (int &x){
    x <<= 1;
    (depth[edge[x].from] < depth[edge[x].to])
        ? x = edge[x].to : x = edge[x].from;
}

//向上推
inline void pushup (int now){
    tree[now] = max (tree[now << 1],tree[now << 1 | 1]);
}

//标记下传,覆盖标记优先
inline void pushdown (int now){
    if (lazyC[now] != -1){
        tree[now << 1] = tree[now << 1 | 1] = lazyC[now];
        lazyC[now << 1] = lazyC[now << 1 | 1] = lazyC[now];
        lazyA[now << 1] = lazyA[now << 1 | 1] = 0;
        lazyC[now] = -1;
    }
    if (lazyA[now]){
        tree[now << 1] += lazyA[now];
        tree[now << 1 | 1] += lazyA[now];
        lazyA[now << 1] += lazyA[now];
        lazyA[now << 1 | 1] += lazyA[now];
        lazyA[now] = 0;
    }
}

//建树
void build (int now,int tl,int tr){
    lazyC[now] = -1; lazyA[now] = 0;
    if (tl == tr){
        tree[now] = value[rk[tl]];
        return;
    }
    int mid = (tl + tr) >> 1;
    build (now << 1,tl,mid);
    build (now << 1 | 1,mid+1,tr);
    pushup (now);
}

//update_Cover
void updateC (int now,int tl,int tr,int left,int right,int change){
    if (right < tl || tr < left)return;
    if (left <= tl && tr <= right){
        tree[now] = lazyC[now] = change;
        lazyA[now] = 0; return;
    }
    pushdown (now);
    int mid = (tl + tr) >> 1;
    updateC (now << 1,tl,mid,left,right,change);
    updateC (now << 1 | 1,mid+1,tr,left,right,change);
    pushup (now);
}

//update_Add
void updateA (int now,int tl,int tr,int left,int right,int change){
    if (right < tl || tr < left)return;
    if (left <= tl && tr <= right){
        tree[now] += change;
        lazyA[now] += change;
        return;
    }
    pushdown (now);
    int mid = (tl + tr) >> 1;
    updateA (now << 1,tl,mid,left,right,change);
    updateA (now << 1 | 1,mid+1,tr,left,right,change);
    pushup (now);
}

void query (int now,int tl,int tr,int left,int right){
    if (right < tl || tr < left)return;
    if (left <= tl && tr <= right){
        res = max (res,tree[now]);
        return;
    }
    pushdown (now);
    int mid = (tl + tr) >> 1;
    query (now << 1,tl,mid,left,right);
    query (now << 1 | 1,mid+1,tr,left,right);
}

//Modify_Range_Cover
inline void MRC (int x,int y,int z){
    while (top[x] != top[y]){
        if (depth[top[x]] < depth[top[y]])swap (x,y);
        updateC (1,1,n,id[top[x]],id[x],z);
        x = father[top[x]];
    }
    if (depth[x] > depth[y])swap (x,y);
    updateC (1,1,n,id[x]+1,id[y],z);
}

//Modify_Range_Add
inline void MRA (int x,int y,int z){
    while (top[x] != top[y]){
        if (depth[top[x]] < depth[top[y]])swap (x,y);
        updateA (1,1,n,id[top[x]],id[x],z);
        x = father[top[x]];
    }
    if (depth[x] > depth[y])swap (x,y);
    updateA (1,1,n,id[x]+1,id[y],z);
}

//Query_Range
inline void QR (int x,int y){
    while (top[x] != top[y]){
        if (depth[top[x]] < depth[top[y]])swap (x,y);
        res = -INF;
        query (1,1,n,id[top[x]],id[x]);
        ans = max (ans,res);
        x = father[top[x]];
    }
    if (depth[x] > depth[y])swap (x,y);
    res = -INF;
    query (1,1,n,id[x]+1,id[y]);
    ans = max (ans,res);
}

void DFS1 (int now,int fa,int d){
    father[now] = fa;
    depth[now] = d;
    size[now] = 1;
    int maxson = -1;
    for (register int i = head[now];i;i = edge[i].next){
        int v = edge[i].to;
        if (v == fa)continue;
        DFS1 (v,now,d+1);
        value[v] = edge[i].v;
        size[now] += size[v];
        if (size[v] > maxson){
            maxson = size[v];
            son[now] = v;
        }
    }
}

void DFS2 (int now,int top_heavy){
    top[now] = top_heavy;
    id[now] = ++dfn;
    rk[dfn] = now;
    if (!son[now])return;
    DFS2 (son[now],top_heavy);
    for (register int i = head[now];i;i = edge[i].next){
        int v = edge[i].to;
        if (v != father[now] && v != son[now])DFS2 (v,v);
    }
}

signed main (){
    Read (n);
    for (register int i = 1;i < n;i++){
        int x,y,z;
        Read (x),Read (y),Read (z);
        connect (x,y,z); connect (y,x,z);
    }
    DFS1 (1,0,1);
    DFS2 (1,1);
    build (1,1,n);
    while ("11ai"){
        char type[10];
        scanf ("%s",type);
        if (type[1] == 't')break; //stop
        if (type[1] == 'a'){      //max
            int x,y;
            Read (x),Read (y);
            ans = -INF; QR (x,y);
            printf ("%lld\n",ans);
        }
        if (type[1] == 'o'){      //cover
            int x,y,z;
            Read (x),Read (y),Read (z);
            MRC (x,y,z);
        }
        if (type[1] == 'd'){      //add
            int x,y,z;
            Read (x),Read (y),Read (z);
            MRA (x,y,z);
        }
        if (type[1] == 'h'){      //change
            int x,y;
            Read (x),Read (y);
            which (x);//应该修改哪里
            updateC (1,1,n,id[x],id[x],y);
        }
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值