【树链剖分】【bzoj2157】: 旅游

本文详细介绍了一种基于树链剖分的算法实现,该算法能够高效地处理涉及树状结构的数据查询和更新操作,包括边权修改、路径最大值、路径最小值及路径权值和等问题。通过两遍深度优先搜索(DFS)预处理和线段树维护,实现了对复杂查询的快速响应。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

Ray 乐忠于旅游,这次他来到了T 城。T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接。为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径。换句话说, T 城中只有N − 1 座桥。Ray 发现,有些桥上可以看到美丽的景色,让人心情愉悦,但有些桥狭窄泥泞,令人烦躁。于是,他给每座桥定义一个愉悦度w,也就是说,Ray 经过这座桥会增加w 的愉悦度,这或许是正的也可能是负的。有时,Ray 看待同一座桥的心情也会发生改变。现在,Ray 想让你帮他计算从u 景点到v 景点能获得的总愉悦度。有时,他还想知道某段路上最美丽的桥所提供的最大愉悦度,或是某段路上最糟糕的一座桥提供的最低愉悦度。

Input

输入的第一行包含一个整数N,表示T 城中的景点个数。景点编号为 0…N − 1。接下来N − 1 行,每行三个整数u、v 和w,表示有一条u 到v,使 Ray 愉悦度增加w 的桥。桥的编号为1…N − 1。|w| <= 1000。输入的第N + 1 行包含一个整数M,表示Ray 的操作数目。接下来有M 行,每行描述了一个操作,操作有如下五种形式: C i w,表示Ray 对于经过第i 座桥的愉悦度变成了w。 N u v,表示Ray 对于经过景点u 到v 的路径上的每一座桥的愉悦度都变成原来的相反数。 SUM u v,表示询问从景点u 到v 所获得的总愉悦度。 MAX u v,表示询问从景点u 到v 的路径上的所有桥中某一座桥所提供的最大愉悦度。 MIN u v,表示询问从景点u 到v 的路径上的所有桥中某一座桥所提供的最小愉悦度。测试数据保证,任意时刻,Ray 对于经过每一座桥的愉悦度的绝对值小于等于1000。

Output

对于每一个询问(操作S、MAX 和MIN),输出答案。

Sample Input

3
0 1 1
1 2 2
8
SUM 0 2
MAX 0 2
N 0 1
SUM 0 2
MIN 0 2
C 1 3
SUM 0 2
MAX 0 2

Sample Output

3
2
1
-1
5
3

HINT

一共有10 个数据,对于第i (1 <= i <= 10) 个数据, N = M = i * 2000。

思路

一个裸的树链剖分,支持边的修改,途径路径最大值,途径路径最小值,路径权值和
首先一遍dfs求每个点的父亲节点和每个点儿子中权值最大的重链
然后一遍dfs进行每条边重新编号
然后维护一下线段树就好了
注意:还有线段树维护时一定不要像以前一样直接建完全二叉树,那样会存不下,导致RE
这里写图片描述
注意:那个lazy值在用后一定要更新,我就因为没更新,T了一篇
说多了都是泪呀…

代码

#include <bits/stdc++.h>
#define N 100050
using namespace std;
struct edge{int v,w,nxt;}a[N<<2];
struct edge_{int u,v,w;}a_[N<<2];
struct pppp{int sum,mi,ma,lazy;}tr[N<<2];
int n,m,he[N],f[N],siz[N],top[N],dis[N],cnt=0,tot=0;
int c[N],ls[N<<2],rs[N<<2];
int root,pp=0,pp_=0,w[N],son[N];
inline void add(int x,int y,int z){
    a[++pp].v=y;a[pp].w=z;a[pp].nxt=he[x];he[x]=pp;
    a[++pp].v=x;a[pp].w=z;a[pp].nxt=he[y];he[y]=pp;
}
inline void add_(int u,int v,int w){
    a_[++pp_].u=u;
    a_[pp_].v=v;
    a_[pp_].w=w;
}
void dfs1(int x,int father){
    siz[x]=1;son[x]=0;
    for(int i=he[x];i;i=a[i].nxt){
        int v=a[i].v;
        if(v!=father){
            f[v]=x;dis[v]=dis[x]+1;
            dfs1(v,x);
            siz[x]+=siz[v];
            if(siz[v]>siz[son[x]])son[x]=v;
        }
    }
}
void dfs2(int x,int father){
    top[x]=father;w[x]=++cnt;
    if(son[x]!=0)dfs2(son[x],father);
    for(int i=he[x];i;i=a[i].nxt){
        int v=a[i].v;
        if(v!=f[x]){
            if(v!=son[x])dfs2(v,v);
            c[w[v]]=a[i].w;
        }
    }
}
void pushup(int rt){
    tr[rt].sum=tr[ls[rt]].sum+tr[rs[rt]].sum;
    tr[rt].ma=max(tr[ls[rt]].ma,tr[rs[rt]].ma);
    tr[rt].mi=min(tr[ls[rt]].mi,tr[rs[rt]].mi);
}
void build(int &rt,int l,int r){
    rt=++tot;tr[rt].lazy=0;
    if(l==r){tr[rt].sum=tr[rt].mi=tr[rt].ma=c[l];return ;}
    int mid=(l+r)>>1;
    build(ls[rt],l,mid);
    build(rs[rt],mid+1,r);
    pushup(rt);
}
void pushdown(int rt){
    int r1,r2;
    if(tr[rt].lazy==1){
        tr[ls[rt]].sum=-tr[ls[rt]].sum;tr[rs[rt]].sum=-tr[rs[rt]].sum;
        r1=tr[ls[rt]].mi;r2=tr[ls[rt]].ma;tr[ls[rt]].mi=-r2;tr[ls[rt]].ma=-r1;
        r1=tr[rs[rt]].mi;r2=tr[rs[rt]].ma;tr[rs[rt]].mi=-r2;tr[rs[rt]].ma=-r1;
        tr[ls[rt]].lazy^=1;tr[rs[rt]].lazy^=1;
        tr[rt].lazy=0;
    }
}
void modify(int rt,int left,int right,int l,int r,int p,int type){
    pushdown(rt);
    if((left==l)&&(right==r)){
        if(type==1){
            tr[rt].sum=p;
            tr[rt].ma=p;tr[rt].mi=p;
            return;
        }
        else{
            tr[rt].lazy^=1;
            tr[rt].sum=-tr[rt].sum;
            int r1,r2;r1=tr[rt].mi;r2=tr[rt].ma;
            tr[rt].mi=-r2;tr[rt].ma=-r1;
            return;
        }
    }
    int mid=(left+right)>>1;
    if(r<=mid)modify(ls[rt],left,mid,l,r,p,type);
    else if(l>=mid+1)modify(rs[rt],mid+1,right,l,r,p,type);
    else{
        modify(ls[rt],left,mid,l,mid,p,type);
        modify(rs[rt],mid+1,right,mid+1,r,p,type);
    }
    pushup(rt);
}
int ask(int rt,int left,int right,int l,int r,int type){
    pushdown(rt);
    if((left==l)&&(right==r)){
        if(type==1)return tr[rt].sum;
        else if(type==2)return tr[rt].ma;
        else return tr[rt].mi;
    }
    int mid=(left+right)>>1;
    if(r<=mid)return ask(ls[rt],left,mid,l,r,type);
    else if(l>=mid+1)return ask(rs[rt],mid+1,right,l,r,type);
    else{
        if(type==1)return ask(ls[rt],left,mid,l,mid,type)+ask(rs[rt],mid+1,right,mid+1,r,type);
        else if(type==2)return max(ask(ls[rt],left,mid,l,mid,type),ask(rs[rt],mid+1,right,mid+1,r,type));
        else return min(ask(ls[rt],left,mid,l,mid,type),ask(rs[rt],mid+1,right,mid+1,r,type));
    }
}char s[10];
int main(){
    scanf("%d",&n);int x,y,z;
    for(int i=1;i<n;++i){
        scanf("%d%d%d",&x,&y,&z);
        ++x;++y;
        add(x,y,z);add_(x,y,z);
    }
    dfs1(1,1);dfs2(1,1);
    build(root,1,cnt);
    scanf("%d",&m);int u,v;
    for(int i=1;i<=m;++i){
        scanf("%s",s);scanf("%d%d",&x,&y);
        if(s[0]=='C'){    
            u=a_[x].u;v=a_[x].v;
            if(f[u]==v)modify(root,1,cnt,w[u],w[u],y,1);
            else modify(root,1,cnt,w[v],w[v],y,1);
        }
        else{
            x++;y++;
            int f1=top[x],f2=top[y];
            if(s[0]=='N'){
                while(f1!=f2){
                    if(dis[f1]<dis[f2]){swap(f1,f2);swap(x,y);}
                    modify(root,1,cnt,w[f1],w[x],0,2);
                    x=f[f1];f1=top[x];
                }
                if(x!=y){
                    if(dis[x]>dis[y])swap(x,y);
                    modify(root,1,cnt,w[son[x]],w[y],0,2);
                }
            }
            else if(s[0]=='S'){
                int ans=0;
                while(f1!=f2){
                    if(dis[f1]<dis[f2]){swap(f1,f2);swap(x,y);}
                    ans+=ask(root,1,cnt,w[f1],w[x],1);
                    x=f[f1];f1=top[x];
                }
                if(x!=y){
                    if(dis[x]>dis[y])swap(x,y);
                    ans+=ask(root,1,cnt,w[son[x]],w[y],1);
                }
                printf("%d\n",ans);
            }
            else if((s[0]=='M')&&(s[1]=='A')){
                int ans=0xefefefef;
                while(f1!=f2){
                    if (dis[f1]<dis[f2]) {swap(f1,f2);swap(x,y);}
                    ans=max(ans,ask(root,1,cnt,w[f1],w[x],2));
                    x=f[f1];f1=top[x];
                }
                if(x!=y){
                    if(dis[x]>dis[y])swap(x,y);
                    ans=max(ans,ask(root,1,cnt,w[son[x]],w[y],2));
                }
                printf("%d\n",ans);
            }
            else{
                int ans=0x3f3f3f3f;
                while(f1!=f2){
                    if(dis[f1]<dis[f2]){swap(f1,f2);swap(x,y);}
                    ans=min(ans,ask(root,1,cnt,w[f1],w[x],3));
                    x=f[f1];f1=top[x];
                }
                if(x!=y){
                    if(dis[x]>dis[y])swap(x,y);
                    ans=min(ans,ask(root,1,cnt,w[son[x]],w[y],3));
                }
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值