bzoj2157 旅游 树链剖分

Description


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

操作有如下五种形式: 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。

Hint


一共有10 个数据,对于第i (1 <= i <= 10) 个数据, N = M = i * 2000。

Solution


裸的树链剖分,这里边的边权可以看成是较低节点的点权,然后取反操作就是最大最小值互换取反,sum取反就行了
细节挺多,码农题

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
const int INF=0x7fffffff;
const int N=400005;
const int E=800005;
struct edge{int x,y,w,next;}e[E];
int ls[N],edCnt=0;
int lazy[N],sum[N],mx[N],mn[N];
int size[N],son[N],len[N],pos[N],dep[N],fa[N],bl[N],cnt=0;
int n,m;
int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}
void addEdge(int x,int y,int w) {
    e[++edCnt]=(edge){x,y,w,ls[x]}; ls[x]=edCnt;
    e[++edCnt]=(edge){y,x,w,ls[y]}; ls[y]=edCnt;
}
void swap(int &x,int &y) {x^=y; y^=x; x^=y;}
void oppo(int x) {
    swap(mx[x],mn[x]);
    mx[x]*=-1; mn[x]*=-1;
    sum[x]*=-1;
}
void dfs1(int now) {
    size[now]=1;
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y==fa[now]) {continue;}
        fa[e[i].y]=now;
        dep[e[i].y]=dep[now]+1;
        len[e[i].y]=e[i].w;
        dfs1(e[i].y);
        size[now]+=size[e[i].y];
    }
}
void dfs2(int now,int up) {
    pos[now]=++cnt; bl[now]=up;
    int mx=0;
    for (int i=ls[now];i;i=e[i].next) {
        if (dep[e[i].y]>dep[now]&&size[e[i].y]>size[mx]) {mx=e[i].y;}
    }
    if (!mx) {return ;}
    son[now]=mx;
    dfs2(mx,up);
    for (int i=ls[now];i;i=e[i].next) {
        if (dep[e[i].y]>dep[now]&&e[i].y!=mx) {dfs2(e[i].y,e[i].y);}
    }
}
void push_down(int now) {
    if (!lazy[now]) {return ;}
    lazy[now<<1]^=lazy[now];
    // if (lazy[now<<1]) {oppo(now<<1);}
    oppo(now<<1);

    lazy[now<<1|1]^=lazy[now];
    // if (lazy[now<<1|1]) {oppo(now<<1|1);}
    oppo(now<<1|1);

    lazy[now]=0;
}
void push_up(int now) {
    mx[now]=max(mx[now<<1],mx[now<<1|1]);
    mn[now]=min(mn[now<<1],mn[now<<1|1]);
    sum[now]=sum[now<<1]+sum[now<<1|1];
}
int query(int now,int tl,int tr,int l,int r,int opt) {
    push_down(now);
    if (tl==l&&tr==r) {
        if (opt==0) {return mx[now];}
        else if (opt==1) {return mn[now];}
        else if (opt==2) {return sum[now];}
    }
    int mid=(tl+tr)>>1;
    if (r<=mid) {return query(now<<1,tl,mid,l,r,opt);}
    else if (l>mid) {return query(now<<1|1,mid+1,tr,l,r,opt);}
    else {
        int retx=query(now<<1,tl,mid,l,mid,opt);
        int rety=query(now<<1|1,mid+1,tr,mid+1,r,opt);
        if (opt==0) {return max(retx,rety);}
        else if (opt==1) {return min(retx,rety);}
        else if (opt==2) {return retx+rety;}
    }
}
void modify(int now,int tl,int tr,int l,int r,int v,int opt) {
    push_down(now);
    if (tl==l&&tr==r) {
        if (opt==1) {oppo(now); lazy[now]=1;}
        else {mx[now]=mn[now]=sum[now]=v;}
        return ;
    }
    int mid=(tl+tr)>>1;
    if (r<=mid) {modify(now<<1,tl,mid,l,r,v,opt);}
    else if (l>mid) {modify(now<<1|1,mid+1,tr,l,r,v,opt);}
    else {
        modify(now<<1,tl,mid,l,mid,v,opt);
        modify(now<<1|1,mid+1,tr,mid+1,r,v,opt);
    }
    push_up(now);
}
int get_ans(int x,int y,int opt) {
    int ret;
    if (opt==0) {ret=-INF;}
    else if (opt==1) {ret=INF;}
    else if (opt==2) {ret=0;}
    while (bl[x]!=bl[y]) {
        if (dep[bl[x]]<dep[bl[y]]) {swap(x,y);}
        if (opt==0) {ret=max(ret,query(1,1,n,pos[bl[x]],pos[x],0));}
        else if (opt==1) {ret=min(ret,query(1,1,n,pos[bl[x]],pos[x],1));}
        else if (opt==2) {ret+=query(1,1,n,pos[bl[x]],pos[x],2);}
        x=fa[bl[x]];
    }
    if (x==y) {return ret;}
    if (dep[x]>dep[y]) {swap(x,y);}
    x=son[x];
    if (opt==0) {ret=max(ret,query(1,1,n,pos[x],pos[y],0));}
    else if (opt==1) {ret=min(ret,query(1,1,n,pos[x],pos[y],1));}
    else if (opt==2) {ret+=query(1,1,n,pos[x],pos[y],2);}
    return ret;
}
void solve_oppo(int x,int y) {
    while (bl[x]!=bl[y]) {
        if (dep[bl[x]]<dep[bl[y]]) {swap(x,y);}
        modify(1,1,n,pos[bl[x]],pos[x],0,1);
        x=fa[bl[x]];
    }
    if (x==y) {return ;}
    if (dep[x]>dep[y]) {swap(x,y);}
    x=son[x];
    modify(1,1,n,pos[x],pos[y],0,1);
}
void buildTree(int now,int l,int r) {
    mx[now]=-INF;
    mn[now]=INF;
    sum[now]=0;
    if (l==r) {return ;}
    int mid=(l+r)>>1;
    buildTree(now<<1,l,mid);
    buildTree(now<<1|1,mid+1,r);
    push_up(now);
}
void solve() {
    dfs1(1);
    dfs2(1,1);
    buildTree(1,1,n);
    rep(i,1,n) {modify(1,1,n,pos[i],pos[i],len[i],2);}
    m=read();
    rep(i,1,m) {
        char opt[5]; scanf("%s",opt);
        int x=read()+1,y=read()+1;
        if (opt[0]=='C') {
            x--,y--;
            if (dep[e[x*2-1].y]>dep[e[x*2].y]) {modify(1,1,n,pos[e[x*2-1].y],pos[e[x*2-1].y],y,0);}
            else {modify(1,1,n,pos[e[x*2].y],pos[e[x*2].y],y,0);}
        } else if (opt[0]=='N') {
            solve_oppo(x,y);
        } else if (opt[0]=='S') {
            int prt=get_ans(x,y,2);
            printf("%d\n",prt);
        } else if (opt[0]=='M'&&opt[1]=='I') {
            int prt=get_ans(x,y,1);
            printf("%d\n",prt);
        } else if (opt[0]=='M'&&opt[1]=='A') {
            int prt=get_ans(x,y,0);
            printf("%d\n",prt);
        }
    }
}
void init() {
    n=read();
    rep(i,2,n) {
        int x=read()+1;
        int y=read()+1;
        int w=read();
        addEdge(x,y,w);
    }
}
int main(void) {
    init();
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值