[BZOJ]2157: 旅游 树链剖分

Description

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

Input

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

Output

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

树链剖分裸题,操作都挺常规的,变相反数只要搞个标记就好了。只不过我实在太弱了(以后要记得及时下传标记啊!),写得很长……不过大部分都是复制粘贴的,所以其实也挺好写的,不要怕……

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=20005;
const int inf=999999999;
struct edge{int x,y,d,next;}e[maxn*5],E[maxn*5];
struct xdtree{int l,r,lc,rc,mx,mn,sum;bool ff;}a[maxn*10];
int tot[maxn],dep[maxn],ys[maxn],Num=0,top[maxn],son[maxn],fa[maxn];
int last[maxn],len=0;
int n,q;
void ins(int x,int y,int d)
{
    int t=++len;
    e[t].y=y;e[t].d=d;e[t].next=last[x];last[x]=t;
}
void work1(int x,int Fa)
{
    son[x]=0;tot[x]=1;dep[x]=dep[Fa]+1;fa[x]=Fa;
    for(int i=last[x];i!=-1;i=e[i].next)
    {
        int y=e[i].y;
        if(y==Fa) continue;
        work1(y,x);
        tot[x]+=tot[y];
        if(tot[son[x]]<tot[y]) son[x]=y;
    }
}
void work2(int x,int t)
{
    ys[x]=++Num;top[x]=t;
    if(son[x]!=0) work2(son[x],t);
    for(int i=last[x];i!=-1;i=e[i].next)
    {
        int y=e[i].y;
        if(y==son[x] || y==fa[x]) continue;
        work2(y,y);
    }
}
int trlen=0;
void build(int l,int r)
{
    int t=++trlen;
    a[t].l=l;a[t].r=r;a[t].sum=0;a[t].mx=-inf;a[t].mn=inf;a[t].ff=false;
    if(l<r)
    {
        int mid=l+r>>1;
        a[t].lc=trlen+1;build(l,mid);
        a[t].rc=trlen+1;build(mid+1,r);
    }
}
void change1(int now,int l,int r)
{
    if(a[now].l==l && a[now].r==r) 
    {
        a[now].ff=!a[now].ff;
        a[now].sum*=-1;
        int Mx=a[now].mx,Mn=a[now].mn;
        a[now].mx=-Mn;a[now].mn=-Mx;
        return;
    }
    int lc=a[now].lc,rc=a[now].rc,mid=a[now].l+a[now].r>>1;
    if(a[now].ff==true)
    {
        a[now].ff=false;
        a[lc].ff=!a[lc].ff;a[rc].ff=!a[rc].ff;
        int Mx,Mn;
        Mx=a[lc].mx;Mn=a[lc].mn;
        a[lc].mx=-Mn;a[lc].mn=-Mx;a[lc].sum*=-1;
        Mx=a[rc].mx;Mn=a[rc].mn;
        a[rc].mx=-Mn;a[rc].mn=-Mx;a[rc].sum*=-1;
    }
    if(r<=mid) change1(lc,l,r);
    else if(l>mid) change1(rc,l,r);
    else change1(lc,l,mid),change1(rc,mid+1,r);
    a[now].sum=a[lc].sum+a[rc].sum;
    a[now].mx=max(a[lc].mx,a[rc].mx);
    a[now].mn=min(a[lc].mn,a[rc].mn);
}
void change(int now,int x,int k)
{
    if(a[now].l==a[now].r) 
    {
        a[now].mx=a[now].mn=a[now].sum=k;
        return;
    }
    int mid=a[now].l+a[now].r>>1,lc=a[now].lc,rc=a[now].rc;
    if(a[now].ff==true)
    {
        a[now].ff=false;
        a[lc].ff=!a[lc].ff;a[rc].ff=!a[rc].ff;
        int Mx,Mn;
        Mx=a[lc].mx;Mn=a[lc].mn;
        a[lc].mx=-Mn;a[lc].mn=-Mx;a[lc].sum*=-1;
        Mx=a[rc].mx;Mn=a[rc].mn;
        a[rc].mx=-Mn;a[rc].mn=-Mx;a[rc].sum*=-1;
    }
    if(x<=mid) change(lc,x,k);
    else change(rc,x,k);
    a[now].sum=a[lc].sum+a[rc].sum;
    a[now].mx=max(a[lc].mx,a[rc].mx);
    a[now].mn=min(a[lc].mn,a[rc].mn);
}
int findmx(int now,int l,int r)
{
    if(a[now].l==l && a[now].r==r) return a[now].mx;
    int mid=a[now].l+a[now].r>>1,lc=a[now].lc,rc=a[now].rc;
    if(a[now].ff==true)
    {
        a[now].ff=false;
        a[lc].ff=!a[lc].ff;a[rc].ff=!a[rc].ff;
        int Mx,Mn;
        Mx=a[lc].mx;Mn=a[lc].mn;
        a[lc].mx=-Mn;a[lc].mn=-Mx;a[lc].sum*=-1;
        Mx=a[rc].mx;Mn=a[rc].mn;
        a[rc].mx=-Mn;a[rc].mn=-Mx;a[rc].sum*=-1;
    }
    if(r<=mid) return findmx(lc,l,r);
    else if(l>mid) return findmx(rc,l,r);
    else return max(findmx(lc,l,mid),findmx(rc,mid+1,r));
}
int findmn(int now,int l,int r)
{
    if(a[now].l==l && a[now].r==r) return a[now].mn;
    int mid=a[now].l+a[now].r>>1,lc=a[now].lc,rc=a[now].rc;
    if(a[now].ff==true)
    {
        //printf("ok\n");
        a[now].ff=false;
        a[lc].ff=!a[lc].ff;a[rc].ff=!a[rc].ff;
        int Mx,Mn;
        Mx=a[lc].mx;Mn=a[lc].mn;
        a[lc].mx=-Mn;a[lc].mn=-Mx;a[lc].sum*=-1;
        Mx=a[rc].mx;Mn=a[rc].mn;
        a[rc].mx=-Mn;a[rc].mn=-Mx;a[rc].sum*=-1;
    }
    if(r<=mid) return findmn(lc,l,r);
    else if(l>mid) return findmn(rc,l,r);
    else return min(findmn(lc,l,mid),findmn(rc,mid+1,r));
}
int getsum(int now,int l,int r)
{
    if(a[now].l==l && a[now].r==r) return a[now].sum;
    int mid=a[now].l+a[now].r>>1,lc=a[now].lc,rc=a[now].rc;
    if(a[now].ff==true)
    {
        //printf("ok\n");
        a[now].ff=false;
        a[lc].ff=!a[lc].ff;a[rc].ff=!a[rc].ff;
        int Mx,Mn;
        Mx=a[lc].mx;Mn=a[lc].mn;
        a[lc].mx=-Mn;a[lc].mn=-Mx;a[lc].sum*=-1;
        Mx=a[rc].mx;Mn=a[rc].mn;
        a[rc].mx=-Mn;a[rc].mn=-Mx;a[rc].sum*=-1;
    }
    if(r<=mid) return getsum(lc,l,r);
    else if(l>mid) return getsum(rc,l,r);
    else return getsum(lc,l,mid)+getsum(rc,mid+1,r);
}
int smx(int x,int y)
{
    int tx=top[x],ty=top[y],ans=-inf;
    while(tx!=ty)
    {
        if(dep[tx]>dep[ty]) swap(tx,ty),swap(x,y);
        ans=max(ans,findmx(1,ys[ty],ys[y]));
        y=fa[ty];ty=top[y];
    }
    if(x==y) return ans;
    else
    {
        if(dep[x]>dep[y]) swap(x,y);
        return max(ans,findmx(1,ys[son[x]],ys[y]));
    }
}
int smn(int x,int y)
{
    int tx=top[x],ty=top[y],ans=inf;
    while(tx!=ty)
    {
        if(dep[tx]>dep[ty]) swap(tx,ty),swap(x,y);
        ans=min(ans,findmn(1,ys[ty],ys[y]));
        y=fa[ty];ty=top[y];
    }
    if(x==y) return ans;
    else
    {
        if(dep[x]>dep[y]) swap(x,y);
        return min(ans,findmn(1,ys[son[x]],ys[y]));
    }
}
int gsum(int x,int y)
{
    int tx=top[x],ty=top[y],ans=0;
    while(tx!=ty)
    {
        if(dep[tx]>dep[ty]) swap(tx,ty),swap(x,y);
        ans+=getsum(1,ys[ty],ys[y]);
        y=fa[ty];ty=top[y];
    }
    if(x==y) return ans;
    else
    {
        if(dep[x]>dep[y]) swap(x,y);
        return ans+getsum(1,ys[son[x]],ys[y]);
    }
}
void Change(int x,int y)
{
    int tx=top[x],ty=top[y];
    while(tx!=ty)
    {
        if(dep[tx]>dep[ty]) swap(tx,ty),swap(x,y);
        change1(1,ys[ty],ys[y]);
        //printf("%d %d\n",ys[ty],ys[y]);
        y=fa[ty];ty=top[y];
    }
    if(x!=y)
    {
        if(dep[x]>dep[y]) swap(x,y);
        change1(1,ys[son[x]],ys[y]);
        //printf("%d %d\n",ys[son[x]],ys[y]);
    }
}
int main()
{
    memset(last,-1,sizeof(last));
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int x,y,d;
        scanf("%d%d%d",&x,&y,&d);x++;y++;
        E[i].x=x;E[i].y=y;E[i].d=d;
        ins(x,y,d);ins(y,x,d);
    }
    scanf("%d",&q);
    dep[1]=0;work1(1,0);
    work2(1,1);
    build(1,Num);
    for(int i=1;i<n;i++)
    {
        if(dep[E[i].x]>dep[E[i].y]) swap(E[i].x,E[i].y);
        change(1,ys[E[i].y],E[i].d);
    }
    //for(int i=1;i<=trlen;i++) printf("%d %d %d %d %d %d\n",i,a[i].l,a[i].r,a[i].mx,a[i].mn,a[i].sum);
    for(int i=1;i<=q;i++)
    {
        char oo[10];
        int x,y;
        scanf("%s%d%d",oo,&x,&y);
        if(oo[0]=='C') change(1,ys[E[x].y],y);
        else if(oo[0]=='N') Change(x+1,y+1);
        else if(oo[0]=='S') printf("%d\n",gsum(x+1,y+1));
        else if(oo[1]=='A') printf("%d\n",smx(x+1,y+1));
        else printf("%d\n",smn(x+1,y+1));
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值