P1505 [国家集训队] 旅游

P1505 [国家集训队] 旅游

题目背景

Ray 乐忠于旅游,这次他来到了 T 城。T 城是一个水上城市,一共有 \(n\) 个景点,有些景点之间会用一座桥连接。为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径。换句话说, T 城中只有 \(n-1\) 座桥。

Ray 发现,有些桥上可以看到美丽的景色,让人心情愉悦,但有些桥狭窄泥泞,令人烦躁。于是,他给每座桥定义一个愉悦度 \(w\),也就是说,Ray 经过这座桥会增加 \(w\) 的愉悦度,这或许是正的也可能是负的。有时,Ray 看待同一座桥的心情也会发生改变。

现在,Ray 想让你帮他计算从 \(u\) 景点到 \(v\) 景点能获得的总愉悦度。有时,他还想知道某段路上最美丽的桥所提供的最大愉悦度,或是某段路上最糟糕的一座桥提供的最低愉悦度。

题目描述

给定一棵 \(n\) 个节点的树,边带权,编号 \(0 \sim n-1\),需要支持五种操作:

  • C i w 将输入的第 \(i\) 条边权值改为 \(w\)
  • N u v\(u,v\) 节点之间的边权都变为相反数;
  • SUM u v 询问 \(u,v\) 节点之间边权和;
  • MAX u v 询问 \(u,v\) 节点之间边权最大值;
  • MIN u v 询问 \(u,v\) 节点之间边权最小值。

保证任意时刻所有边的权值都在 \([-1000,1000]\) 内。

输入格式

第一行一个正整数 \(n\),表示节点个数。
接下来 \(n-1\) 行,每行三个整数 \(u,v,w\),表示 \(u,v\) 之间有一条权值为 \(w\) 的边,描述这棵树。
然后一行一个正整数 \(m\),表示操作数。
接下来 \(m\) 行,每行表示一个操作。

输出格式

对于每一个询问操作,输出一行一个整数表示答案。

说明/提示

【数据范围】

对于 \(100\%\) 的数据,\(1\le n,m \le 2\times 10^5\)

Solution:

一道十分经典的树链剖分练手题,我们将边权改点权(每个点对应其认父边的边长)

然后我们在线段树上维护一下 \(mn,mx,sum\) 就好了。

Code:

#include<bits/stdc++.h>
#define ls x<<1
#define rs x<<1|1
const int N=2e5+5;
const int inf=1e9;
using namespace std;
int head[N],dfn[N],siz[N],son[N],dis[N],top[N],dep[N],val[N];
int id[N],fa[N];
char c[50];
int e_cnt,n,m,dfn_cnt;
struct Edge{
    int to,nxt,w;
}e[N<<1];
struct Tree{
    int l,r,ma,mi,sum,tag;
}t[N<<2];
inline void pushup(int x)
{
    t[x].mi=min(t[ls].mi,t[rs].mi);t[x].ma=max(t[ls].ma,t[rs].ma);
    t[x].sum=t[ls].sum+t[rs].sum;
    return ;
}
inline void build(int x,int l,int r)
{
    t[x].tag=0;
    t[x].l=l,t[x].r=r;
    if(l==r)
    {
        t[x].mi=t[x].ma=t[x].sum=dis[id[l]];
        return;
    }
    int mid=l+r>>1;
    build(ls,l,mid);build(rs,mid+1,r);
    pushup(x);
}
inline void pushdown(int x)
{
    if(!t[x].tag)return;
    t[ls].mi=-t[ls].mi;t[rs].mi=-t[rs].mi;
    t[ls].ma=-t[ls].ma;t[rs].ma=-t[rs].ma;
    t[ls].sum=-t[ls].sum;t[rs].sum=-t[rs].sum;
    t[ls].tag^=1;t[rs].tag^=1;
    swap(t[ls].mi,t[ls].ma);swap(t[rs].mi,t[rs].ma);
    t[x].tag=0;
    return;
}
inline void upd_tag(int x,int ll,int rr,int tag)
{
    if(ll<=t[x].l&&t[x].r<=rr)
    {
        t[x].tag^=tag;
        t[x].ma=-t[x].ma;t[x].mi=-t[x].mi;t[x].sum=-t[x].sum;
        swap(t[x].mi,t[x].ma);
        return;
    }
    int mid=t[x].l+t[x].r>>1;
    pushdown(x);
    if(ll<=mid)upd_tag(ls,ll,rr,tag);
    if(rr>mid)upd_tag(rs,ll,rr,tag);
    pushup(x);
}
inline void upd_val(int x,int pos,int val)
{
    if(t[x].l==t[x].r)
    {
        t[x].mi=t[x].ma=t[x].sum=val;
        return;
    }
    int mid=t[x].l+t[x].r>>1;
    pushdown(x);
    if(pos<=mid)upd_val(ls,pos,val);
    else upd_val(rs,pos,val);
    pushup(x);
}
inline void query(int x,int ll,int rr,Tree &res)
{
    if(ll<=t[x].l&&t[x].r<=rr)
    {
        res.sum+=t[x].sum;res.ma=max(res.ma,t[x].ma);res.mi=min(res.mi,t[x].mi);
        return ;
    }
    int mid=t[x].l+t[x].r>>1;
    pushdown(x);
    if(ll<=mid)query(ls,ll,rr,res);
    if(rr>mid)query(rs,ll,rr,res);
    pushup(x);
}
inline void add(int x,int y,int w)
{
    e[++e_cnt]=(Edge){y,head[x],w};
    head[x]=e_cnt;
}
inline void dfs1(int x,int f)
{
    fa[x]=f;siz[x]=1;dep[x]=dep[f]+1;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(to==fa[x])continue;
        dis[to]=e[i].w;
        dfs1(to,x);
        siz[x]+=siz[to];
        if(siz[to]>siz[son[x]])son[x]=to;
    }
}
inline void dfs2(int x,int tp)
{
    top[x]=tp;dfn[x]=++dfn_cnt;id[dfn_cnt]=x;
    if(!son[x])return;
    dfs2(son[x],tp);
    for(int i=head[x];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(to==fa[x]||to==son[x])continue;
        dfs2(to,to);
    }
}
inline void chain_upd_tag(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        int tp=top[x];
        upd_tag(1,dfn[tp],dfn[x],1);
        x=fa[tp];
    }
    if(dep[x]<dep[y])swap(x,y);
    if(x==y)return;
    upd_tag(1,dfn[y]+1,dfn[x],1);
    return ;
}
inline void chain_query(int x,int y,Tree &res)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        int tp=top[x];
        query(1,dfn[tp],dfn[x],res);
        x=fa[tp];
    }
    if(dep[x]<dep[y])swap(x,y);
    if(x==y)return ;
    query(1,dfn[y]+1,dfn[x],res);
}
inline void solve()
{
    cin>>n;
    for(int i=1,x,y,w;i<n;i++)
    {
        scanf("%d%d%d",&x,&y,&w);
        add(x+1,y+1,w);add(y+1,x+1,w);
    }
    dfs1(1,0);dfs2(1,1);
    build(1,1,n);
    cin>>m;
    int id=1;
    for(int i=1,u,v;i<=m;i++)
    {
        scanf("%s",c);
        scanf("%d%d",&u,&v);
        if(c[0]=='C')
        {
            int uu=e[(u<<1)].to,vv=e[(u<<1)-1].to;
            if(dep[uu]<dep[vv])swap(uu,vv);
            upd_val(1,dfn[uu],v);
            continue;
        }
        if(c[0]=='N')
        {
            chain_upd_tag(u+1,v+1);
            continue;
        }
        Tree ans=(Tree){0,0,-inf,inf,0,0};
        chain_query(u+1,v+1,ans);
        if(c[1]=='U')
        printf("%d\n",ans.sum);
        if(c[1]=='A')
        printf("%d\n",ans.ma);
        if(c[1]=='I')
        printf("%d\n",ans.mi);
    }
}
#undef ls
#undef rs
int main()
{
   // freopen("P1505_1.in","r",stdin);freopen("trip.out","w",stdout);
    solve();
    return 0;
}
posted @ 2025-04-10 13:10  liuboom  阅读(24)  评论(0)    收藏  举报