• [国家集训队]旅游


    [国家集训队]旅游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;
    }
    
  • 相关阅读:
    eclipse A Java Runtime Environment(JRE)
    【Android】自己定义圆形ImageView(圆形头像 可指定大小)
    addEventListener()、attachEvent()和removeEventListener()、detachEvent()的差别?
    Android 自己定义控件实现刮刮卡效果 真的就仅仅是刮刮卡么
    qt自己定义搜索框(超简单,带效果图)
    OpenCV基础篇之像素操作对照度调节
    NYOJ 16 矩形嵌套 (DAG上的DP)
    hdu 1247 Hat’s Words(从给的单词中找hat&#39;s word 并按字典序输出)
    Android学习路线(十八)支持不同设备——支持不同的屏幕
    移动智能设备功耗优化系列--前言(NVIDIA资深project师分享)
  • 原文地址:https://www.cnblogs.com/sdzwyq/p/8469843.html
Copyright © 2020-2023  润新知