[国家集训队]旅游

[国家集训队]旅游https://www.luogu.org/problemnew/show/P1505

题目描述

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

输入格式:

输入的第一行包含一个整数(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)

输出格式:

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

输入样例:

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

输出样例:

3
2
1
-1
5
3


树链剖分
单点修改,区间修改,区间(最大值,最小值,和)查询
关键在于区间修改,题目让取反,可以开一个(bool)(opp[])(相当与(lazy))表示是否需要取反,每次opp[]^=1;
注意:
1.题目中没说明(N)的范围,我是开到(5w)(AC)的.
2.(Pushdown)的时候不止修改(sum),还有(Max)(Min).
3.将边权(父亲-->儿子)赋给儿子的点权
4.由于点权的特殊性,在修改和查询中当节点(x,y)跳到同一条链上时,特判(x==y)且查询[修改]区间为((dfn[x]+1~dfn[y]))

#define RG register
#include<cstdio>
#include<iostream>
using namespace std;
const int N=51000;
inline int read()
{
    RG int x=0,w=1;RG char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}
int n,m,cnt,ct;
int last[N],size[N],fa[N],dep[N],son[N],val[N],top[N],dfn[N],rk[N];
int sum[N<<2],Max[N<<2],Min[N<<2];
bool opp[N<<2];
struct edge{int to,next,w;}e[N<<1];
inline void insert(int u,int v,int w)
{
    e[++cnt]=(edge){v,last[u],w};last[u]=cnt;
    e[++cnt]=(edge){u,last[v],w};last[v]=cnt;
}
void dfs1(int now)
{
    size[now]=1;
    for(int i=last[now];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa[now])continue;
        fa[v]=now;
        val[v]=e[i].w;
        dep[v]=dep[now]+1;
        dfs1(v);
        size[now]+=size[v];
        if(size[v]>size[son[now]])son[now]=v;
    }
}
void dfs2(int now,int Top)
{
    top[now]=Top;dfn[now]=++ct;rk[ct]=now;
    if(son[now])dfs2(son[now],Top);
    for(int i=last[now];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa[now]||v==son[now])continue;
        dfs2(v,v);
    }
}
inline void Pushup(int root)
{
    sum[root]=sum[root<<1]+sum[root<<1|1];
    Max[root]=max(Max[root<<1],Max[root<<1|1]);
    Min[root]=min(Min[root<<1],Min[root<<1|1]);
}
void Build(int root,int l,int r)
{
    if(l==r){sum[root]=Max[root]=Min[root]=val[rk[l]];return;}
    int mid=(l+r)>>1;
    Build(root<<1,l,mid);
    Build(root<<1|1,mid+1,r);
    Pushup(root);
}
inline void Pushdown(int root)
{
    if(!opp[root])return;
    opp[root]=false;
    sum[root<<1]=-sum[root<<1];sum[root<<1|1]=-sum[root<<1|1];//sum[]直接取反
    swap(Max[root<<1],Min[root<<1]);Max[root<<1]=-Max[root<<1];Min[root<<1]=-Min[root<<1];//max[]和min[]先交换后取反
    swap(Max[root<<1|1],Min[root<<1|1]);Max[root<<1|1]=-Max[root<<1|1];Min[root<<1|1]=-Min[root<<1|1];
    opp[root<<1]^=1;opp[root<<1|1]^=1;//懒标记取反
}
void Modify_Point(int root,int l,int r,int s,int k)
{
    Pushdown(root);
    if(l==s&&r==s){Max[root]=Min[root]=sum[root]=k;return;}//注意max,min,sum都要修改
    int mid=(l+r)>>1;
    if(s<=mid)Modify_Point(root<<1,l,mid,s,k);
    else Modify_Point(root<<1|1,mid+1,r,s,k);
    Pushup(root);
}
void Modify(int root,int l,int r,int ll,int rr)
{
    Pushdown(root);
    if(ll<=l&&r<=rr)
    {
        opp[root]^=1;
        sum[root]=-sum[root];
        swap(Max[root],Min[root]);
        Max[root]=-Max[root];
        Min[root]=-Min[root];
        return;
    }
    int mid=(l+r)>>1;
    if(ll<=mid)Modify(root<<1,l,mid,ll,rr);
    if(mid<rr)Modify(root<<1|1,mid+1,r,ll,rr);
    Pushup(root);
}
int Query(int root,int l,int r,int ll,int rr,int op)
{
    Pushdown(root);
    if(ll<=l&&r<=rr)
    {
        if(op==1)return sum[root];
        if(op==2)return Max[root];
        if(op==3)return Min[root];
    }
    int mid=(l+r)>>1,Ans;
    if(op==1)Ans=0;
    if(op==2)Ans=-1e9;
    if(op==3)Ans=1e9;
    if(ll<=mid)
    {
        if(op==1)Ans+=Query(root<<1,l,mid,ll,rr,op);
        if(op==2)Ans=max(Ans,Query(root<<1,l,mid,ll,rr,op));
        if(op==3)Ans=min(Ans,Query(root<<1,l,mid,ll,rr,op));
    }
    if(mid<rr)
    {
        if(op==1)Ans+=Query(root<<1|1,mid+1,r,ll,rr,op);
        if(op==2)Ans=max(Ans,Query(root<<1|1,mid+1,r,ll,rr,op));
        if(op==3)Ans=min(Ans,Query(root<<1|1,mid+1,r,ll,rr,op));
    }
    return Ans;
}
inline void Modify_Opp(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        Modify(1,1,n,dfn[top[x]],dfn[x]);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    if(x!=y)Modify(1,1,n,dfn[x]+1,dfn[y]);//dfn[x]对应的点权不在修改范围中
}
inline int Query_Tree(int x,int y,int op)//op=1:查询和;op=2:查询最大值;op=3:查询最小值
{
    int Ans;
    if(op==1)Ans=0;
    if(op==2)Ans=-1e9;//注意初始化
    if(op==3)Ans=1e9;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        if(op==1)Ans+=Query(1,1,n,dfn[top[x]],dfn[x],op);
        if(op==2)Ans=max(Ans,Query(1,1,n,dfn[top[x]],dfn[x],op));
        if(op==3)Ans=min(Ans,Query(1,1,n,dfn[top[x]],dfn[x],op));
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    if(x==y)return Ans;
    if(op==1)Ans+=Query(1,1,n,dfn[x]+1,dfn[y],op);
    if(op==2)Ans=max(Ans,Query(1,1,n,dfn[x]+1,dfn[y],op));
    if(op==3)Ans=min(Ans,Query(1,1,n,dfn[x]+1,dfn[y],op));
    return Ans;
}
int main()
{
    n=read();
    for(int i=1;i<n;i++)
    {
        int a=read(),b=read(),c=read();
        insert(a,b,c);
    }
    dep[0]=1;
    dfs1(0);
    dfs2(0,0);
    Build(1,1,n);
    m=read();
    RG char act[5];
    RG int u,v;
    while(m--)
    {
        scanf("%s",act);
        if(act[0]=='C'){u=read();v=read();Modify_Point(1,1,n,dfn[u],v);};
        if(act[0]=='N'){u=read();v=read();Modify_Opp(u,v);};
        if(act[0]=='S'){u=read();v=read();printf("%d
",Query_Tree(u,v,1));}
        if(act[1]=='A'){u=read();v=read();printf("%d
",Query_Tree(u,v,2));}
        if(act[1]=='I'){u=read();v=read();printf("%d
",Query_Tree(u,v,3));}
    }
    return 0;
}
原文地址:https://www.cnblogs.com/sdzwyq/p/8469843.html