P1505 [国家集训队]旅游(树链剖分)

题目链接:https://www.luogu.org/problemnew/show/P1505

 

题目大意:

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

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

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

 

题目思路:边权转点权,权给儿子。 lazy标记,取相反数,maxx取相反给minn,minn取相反给maxx,sum取相反数

 

以下是代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define inf 0x7fffffff
const int MAXN = 2e5+5;
struct nod{
    int to,w;
}p;
char s[MAXN];
int fa[MAXN],siz[MAXN],son[MAXN],rk[MAXN],dep[MAXN],dfn[MAXN],top[MAXN],w[MAXN],tot;
vector<nod>v[MAXN];

void dfs1(int u,int f){
    dep[u]=dep[f]+1;
    siz[u]=1;
    fa[u]=f;
    son[u]=0;
    int len=v[u].size();
    rep(i,0,len-1){
        int to=v[u][i].to;
        if(to==f)continue;
        w[to]=v[u][i].w;
        dfs1(to,u);
        siz[u]+=siz[to];
        if(siz[to]>siz[son[u]]){
            son[u]=to;
        }
    }
}

void dfs2(int u,int tp){
    dfn[u]=++tot;rk[tot]=u;
    top[u]=tp;
    int len=v[u].size();
    if(son[u])dfs2(son[u],tp);
    rep(i,0,len-1){
        int to=v[u][i].to;
        if(to==fa[u]||to==son[u])continue;
        dfs2(to,to);
    }
}

struct edge{
    int x,y;
}b[MAXN];

struct node{
    int l,r,sum,maxx,minn,lazy;
}a[MAXN<<2];

void build(int rt,int l,int r){
    a[rt].l=l,a[rt].r=r,a[rt].lazy=0;
    if(l==r){
        a[rt].sum=a[rt].maxx=a[rt].minn=w[rk[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    a[rt].sum=a[rt<<1].sum+a[rt<<1|1].sum;
    a[rt].maxx=max(a[rt<<1].maxx,a[rt<<1|1].maxx);
    a[rt].minn=min(a[rt<<1].minn,a[rt<<1|1].minn);
}

void spread(int rt){
    if(a[rt].lazy){
        a[rt<<1].sum=-a[rt<<1].sum;
        a[rt<<1|1].sum=-a[rt<<1|1].sum;
        int temp=a[rt<<1].minn;
        a[rt<<1].minn=-a[rt<<1].maxx;
        a[rt<<1].maxx=-temp;
        temp=a[rt<<1|1].minn;
        a[rt<<1|1].minn=-a[rt<<1|1].maxx;
        a[rt<<1|1].maxx=-temp;
        a[rt<<1].lazy^=1;
        a[rt<<1|1].lazy^=1;
        a[rt].lazy=0;
    }
}

void update(int rt,int x,int y){
    if(a[rt].l==x&&a[rt].r==x){
        a[rt].sum=a[rt].maxx=a[rt].minn=y;
        return;
    }
    spread(rt);
    int mid=(a[rt].l+a[rt].r)>>1;
    if(x<=mid)update(rt<<1,x,y);
    else update(rt<<1|1,x,y);
    a[rt].sum=a[rt<<1].sum+a[rt<<1|1].sum;
    a[rt].maxx=max(a[rt<<1].maxx,a[rt<<1|1].maxx);
    a[rt].minn=min(a[rt<<1].minn,a[rt<<1|1].minn);
}

void update2(int rt,int l,int r){
    if(a[rt].l>=l&&a[rt].r<=r){
        a[rt].sum*=-1;
        int temp=a[rt].minn;
        a[rt].minn=-a[rt].maxx;
        a[rt].maxx=-temp;
        a[rt].lazy^=1;
        return;
    }
    spread(rt);
    int mid=(a[rt].l+a[rt].r)>>1;
    if(l<=mid)update2(rt<<1,l,r);
    if(r>mid)update2(rt<<1|1,l,r);
    a[rt].sum=a[rt<<1].sum+a[rt<<1|1].sum;
    a[rt].maxx=max(a[rt<<1].maxx,a[rt<<1|1].maxx);
    a[rt].minn=min(a[rt<<1].minn,a[rt<<1|1].minn);
}

void update1(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        update2(1,dfn[top[x]],dfn[x]);
        x=fa[top[x]];
    }
    if(dfn[x]>dfn[y])swap(x,y);
    update2(1,dfn[x]+1,dfn[y]);
}

int query(int rt,int l,int r){
    if(a[rt].l>=l&&a[rt].r<=r){
        return a[rt].sum;
    }
    spread(rt);
    int mid=(a[rt].l+a[rt].r)>>1,ans=0;
    if(l<=mid)ans+=query(rt<<1,l,r);
    if(r>mid)ans+=query(rt<<1|1,l,r);
    return ans;
}

int query1(int x,int y){
    int ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=query(1,dfn[top[x]],dfn[x]);
        x=fa[top[x]];
    }
    if(dfn[x]>dfn[y])swap(x,y);
    ans+=query(1,dfn[x]+1,dfn[y]);
    return ans;
}

int query2(int rt,int l,int r){
    if(a[rt].l>=l&&a[rt].r<=r){
        return a[rt].maxx;
    }
    spread(rt);
    int mid=(a[rt].l+a[rt].r)>>1,ans=-inf;
    if(l<=mid)ans=max(ans,query2(rt<<1,l,r));
    if(r>mid)ans=max(ans,query2(rt<<1|1,l,r));
    return ans;
}

int query3(int x,int y){
    int ans=-inf;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=max(ans,query2(1,dfn[top[x]],dfn[x]));
        x=fa[top[x]];
    }
    if(dfn[x]>dfn[y])swap(x,y);
    ans=max(ans,query2(1,dfn[x]+1,dfn[y]));
    return ans;
}

int query4(int rt,int l,int r){
    if(a[rt].l>=l&&a[rt].r<=r){
        return a[rt].minn;
    }
    spread(rt);
    int mid=(a[rt].l+a[rt].r)>>1,ans=inf;
    if(l<=mid)ans=min(ans,query4(rt<<1,l,r));
    if(r>mid)ans=min(ans,query4(rt<<1|1,l,r));
    return ans;
}

int query5(int x,int y){
    int ans=inf;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=min(ans,query4(1,dfn[top[x]],dfn[x]));
        x=fa[top[x]];
    }
    if(dfn[x]>dfn[y])swap(x,y);
    ans=min(ans,query4(1,dfn[x]+1,dfn[y]));
    return ans;
}

int main(){
    int n,m,x,y,z;
    //while(~){
        scanf("%d",&n);
        rep(i,1,n)v[i].clear();
        rep(i,1,n-1){
            scanf("%d%d%d",&x,&y,&z);
            x++;y++;
            b[i].x=x,b[i].y=y;
            p.to=y,p.w=z;
            v[x].push_back(p);
            p.to=x,p.w=z;
            v[y].push_back(p);
        }
        dep[0]=0,tot=0;
        w[0]=w[1]=0;
        dfs1(1,0);
        dfs2(1,1);
        build(1,1,n);
        scanf("%d",&m);
        while(m--){
            scanf("%s%d%d",s,&x,&y);
            if(s[0]=='C'){
                int u=b[x].x,v=b[x].y;
                if(dep[u]<dep[v])swap(u,v);
                update(1,dfn[u],y);
            }
            else if(s[0]=='N'){
                x++;y++;
                update1(x,y);
            }
            else if(s[0]=='S'){
                x++;y++;
                int ans=query1(x,y);
                printf("%d\n",ans);
            }
            else if(s[1]=='A'){
                x++;y++;
                int ans=query3(x,y);
                printf("%d\n",ans);
            }
            else if(s[1]=='I'){
                x++;y++;
                int ans=query5(x,y);
                printf("%d\n",ans);
            }
        }
   // }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值