BZOJ2157 旅游

BZOJ2157 旅游


题目描述

传送门

题目分析

给出一棵树,然后要求维护链边权和,链上最大最小值,以及链乘\(-1\)

考虑使用树链剖分,先把边权转化为父节点点权,然后直接维护就可以了。问题主要在于最小最大值在下传标记时的更改。显而易见的是这俩数都取反之后直接\(swap\)就可以了。

注意,根据线段树写法不同要在树剖里特判\(x=y\)的情况。

可笑的是这个题对于取相反数操作直接暴力递归到叶子节点也有极其优秀的表现。数据还真是。。。甚至某些错误写法也可通过。。。这。。。

是代码呢

#include <bits/stdc++.h>
using namespace std;
#define ls ((rt<<1))
#define rs ((rt<<1)|1)
#define mid ((l+r)>>1)
#define ll long long
const int MAXN=1e5+7;
const int inf=1e9+7;
int f[MAXN],id[MAXN],w[MAXN],at[MAXN],top[MAXN],dep[MAXN],wson[MAXN],size[MAXN],val[MAXN],cnt,n,m;
int mx[MAXN<<2],mn[MAXN<<2],rev[MAXN<<2],head[MAXN],num;
ll sum[MAXN<<2];
char s[5];
struct po{
    int nxt,to,dis,id;
}edge[MAXN];
inline int read()
{
    int x=0,c=1;
    char ch=' ';
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    while(ch=='-')c*=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*c;
}
inline void add_edge(int from,int to,int dis,int id)
{
    edge[++num].nxt=head[from];edge[num].to=to;edge[num].dis=dis;edge[num].id=id;head[from]=num;
    edge[++num].nxt=head[to];edge[num].to=from;edge[num].dis=dis;edge[num].id=id;head[to]=num;
}
inline void dfs(int u,int fa)
{
    size[u]=1;f[u]=fa;dep[u]=dep[fa]+1;
    for(int i=head[u];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==fa) continue;
        dfs(v,u);
        val[v]=edge[i].dis;
        at[edge[i].id]=v;
        size[u]+=size[v];
        if(size[wson[u]]<size[v]) wson[u]=v;
    }
}
inline void dfs2(int u,int tp)
{
    id[u]=++cnt;top[u]=tp;w[cnt]=val[u];
    if(wson[u]) dfs2(wson[u],tp);
    for(int i=head[u];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==f[u]||v==wson[u]) continue;
        dfs2(v,v);
    }
}
inline void pushup(int rt)
{
    sum[rt]=sum[ls]+sum[rs];
    mx[rt]=max(mx[ls],mx[rs]);
    mn[rt]=min(mn[ls],mn[rs]);
}
inline void build(int l,int r,int rt)
{
    rev[rt]=1;
    if(l==r){
        sum[rt]=mx[rt]=mn[rt]=w[l];
        return;
    }
    build(l,mid,ls);build(mid+1,r,rs);
    pushup(rt);
}
inline void pushdown(int l,int r,int rt)
{
    if(rev[rt]!=1){
        rev[ls]*=-1;rev[rs]*=-1;
        sum[ls]=-sum[ls]; sum[rs]=-sum[rs];
        int t=mx[ls];mx[ls]=-mn[ls];mn[ls]=-t;
        t=mx[rs];mx[rs]=-mx[rs];mn[rs]=-t;
        rev[rt]=1;
    }
}
inline void change(int x,int k,int l,int r,int rt)
{
    if(l==r){
        sum[rt]=mx[rt]=mn[rt]=k;
        return;
    }
    pushdown(l,r,rt);
    if(x<=mid) change(x,k,l,mid,ls);
    else change(x,k,mid+1,r,rs);
    pushup(rt);
}
//inline void update(int L,int R,int l,int r,int rt)
//{
//  if(L<=l&&r<=R){
//      sum[rt]=-sum[rt];
//      int t=mx[rt];
//      mx[rt]=-mn[rt];
//      mn[rt]=-t;
//      rev[rt]*=-1;
//      return;
//  }
//  pushdown(l,r,rt);
//  if(L<=mid) update(L,R,l,mid,ls);
//  if(R>mid) update(L,R,mid+1,r,rs);
//  pushup(rt);
//}
inline void update(int L,int R,int l,int r,int rt)
{
    if(r<L||l>R) return;
    if(l==r){
        sum[rt]*=-1;
        mx[rt]*=-1;
        mn[rt]*=-1;
        return;
    }
    update(L,R,l,mid,ls);update(L,R,mid+1,r,rs);
    pushup(rt);
}
inline ll query_sum(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R) return sum[rt];
    ll ans=0;
    pushdown(l,r,rt);
    if(L<=mid) ans+=query_sum(L,R,l,mid,ls);
    if(R>mid) ans+=query_sum(L,R,mid+1,r,rs);
    return ans;
}
inline int query_mx(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R) return mx[rt];
    pushdown(l,r,rt);
    int maxx=-inf;
    if(L<=mid) maxx=max(maxx,query_mx(L,R,l,mid,ls));
    if(R>mid) maxx=max(maxx,query_mx(L,R,mid+1,r,rs));
    return maxx;
}
inline int query_mn(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R) return mn[rt];
    pushdown(l,r,rt);
    int minn=inf;
    if(L<=mid) minn=min(minn,query_mn(L,R,l,mid,ls));
    if(R>mid) minn=min(minn,query_mn(L,R,mid+1,r,rs));
    return minn;
}
inline void Update(int x,int y)
{
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        update(id[top[x]],id[x],1,n,1);
        x=f[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    update(id[x]+1,id[y],1,n,1);
}
inline ll Query_sum(int x,int y)
{
    ll ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        ans+=query_sum(id[top[x]],id[x],1,n,1);
        x=f[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    ans+=query_sum(id[x]+1,id[y],1,n,1);
    return ans;
}
inline int Query_mx(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,query_mx(id[top[x]],id[x],1,n,1));
        x=f[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    ans=max(ans,query_mx(id[x]+1,id[y],1,n,1));
    return ans;
}
inline int Query_mn(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,query_mn(id[top[x]],id[x],1,n,1));
        x=f[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    ans=min(ans,query_mn(id[x]+1,id[y],1,n,1));
    return ans;
}
int main()
{
//  freopen("data.in","r",stdin);
//  freopen("my.out","w",stdout);
    n=read();
    for(int i=1;i<n;i++){
        int x=read()+1,y=read()+1,l=read();
        add_edge(x,y,l,i);
    }
    dfs(1,0);dfs2(1,1);build(1,n,1);
    m=read();
    while(m--){
        scanf("%s",s);
        int x=read()+1,y=read()+1;
        if(s[0]=='C'){
            x--;y--;
            change(id[at[x]],y,1,n,1);
        } else if(s[0]=='N'){
            Update(x,y);
        } else if(s[0]=='S'){
            printf("%lld\n", Query_sum(x,y));
        } else if(s[0]=='M'){
            if(s[1]=='I'){
                printf("%d\n", Query_mn(x,y));
            } else printf("%d\n", Query_mx(x,y));
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/victorique/p/10247011.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值