[BZOJ2157]旅行(树链剖分)

Description
原题意太恶心,我重新整理一个吧。。
有n个点,n-1条边(一棵树),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。
注意,修改是单边修改并不是单点,还有点的编号是从0到n-1,这是这道题最大的难点(雾

SimpleInput

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

SimpleOutput

3
2
1
-1
5
3


首先大的方向,这题是在树上做操作,同时有修改,求极值等操作,妥妥树剖没得说。
那么对于每一个操作来讲一下做法吧!
1、修改
首先要注意是单边修改,不是单点修改。 那么我们平常学的树剖是单点修改,如何把单边修改等价于单点修改呢?
我们只要将一条边等效于他两端的两个点深度较大的那一个。为什么不是深度较小的那个呢?
因为这样的话点和边就无法一一对应了,如果选深度较大的那个对应,点和边就可以一一对应。

2、成段取反
打lazy标记,同时最大值和最小值互换(相反数嘛)

3、4、5、区间求和,最大值,最小值
这三个操作都是类似的,维护三个值即可。

总结:
RE了很久然后WA了很久,
最后找了班里有权限号的同学要了数据wwww
不要数据估计还要好久、、
两个教训:
1、不要手贱交换一下输入数据里面的u、v,
2、solve里面(x==y)时,如果操作的是边,不要手贱再去维护一下,因为我们把边的值放在深度较深的点上,如果这是后再去维护就是维护的上面那条边的值。


#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=310000;
struct node
{
    int x,y,c,next;
}a[maxn*2]; int len,last[maxn];
void ins(int x,int y,int c)
{
    len++;
    a[len].x=x;a[len].y=y;a[len].c=c;
    a[len].next=last[x];last[x]=len;
}
int fa[maxn],dep[maxn],son[maxn],tot[maxn];
int pre_tree_node(int x)
{
    son[x]=0,tot[x]=1;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa[x])
        {
            fa[y]=x;
            dep[y]=dep[x]+1;
            pre_tree_node(y);
            if(tot[son[x]]<tot[y]) son[x]=y;
            tot[x]+=tot[y];
        }
    }
}
int ys[maxn],z,top[maxn];
void pre_tree_edge(int x,int tp)
{
    ys[x]=++z; top[x]=tp;
    if(son[x]!=0) {pre_tree_edge(son[x],tp);}
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa[x] && y!=son[x])
        {
            pre_tree_edge(y,y);
        }
    }
}
struct trnode
{
    int lc,rc,l,r;
    int sum;
    int mx,mn;
    bool gg;
}tr[maxn*4]; int trlen;
void fz(int now)
{
    int lc=tr[now].lc,rc=tr[now].rc;
    swap(tr[lc].mx,tr[lc].mn);
    tr[lc].mx*=-1;
    tr[lc].mn*=-1;
    tr[lc].sum*=-1;
    swap(tr[rc].mx,tr[rc].mn);
    tr[rc].mx*=-1;
    tr[rc].mn*=-1;
    tr[rc].sum*=-1;
    tr[lc].gg^=1,tr[rc].gg^=1;
    tr[now].gg=false;
}
void bt(int l,int r)
{
    trlen++; int now=trlen;
    tr[now].l=l,tr[now].r=r;
    tr[now].lc=tr[now].rc=-1;
    tr[now].mx=tr[now].mn=tr[now].sum=0;
    tr[now].gg=false;
    if(l<r)
    {
        int mid=(l+r)/2;
        tr[now].lc=trlen+1; bt(l,mid);
        tr[now].rc=trlen+1; bt(mid+1,r);
    }
}
void change(int now,int x,int c)
{
    if(tr[now].l==tr[now].r)
    {
        tr[now].mx=tr[now].mn=tr[now].sum=c;
        return;
    }
    if(tr[now].gg) fz(now);
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(tr[now].l+tr[now].r)/2;
    if(x<=mid) {change(lc,x,c);}
    else if(mid+1<=x){ change(rc,x,c);}
    tr[now].mx=max(tr[lc].mx,tr[rc].mx);
    tr[now].mn=min(tr[lc].mn,tr[rc].mn);
    tr[now].sum=tr[lc].sum+tr[rc].sum;
}
void change_fz(int now,int l,int r)
{
    if(tr[now].l==l && tr[now].r==r)
    {
        tr[now].gg^=1;
        swap(tr[now].mx,tr[now].mn);
        tr[now].mx*=-1;
        tr[now].mn*=-1;
        tr[now].sum*=-1;
        return;
    }
    if(tr[now].gg) fz(now);
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid) {change_fz(lc,l,r);}
    else if(mid+1<=l){ change_fz(rc,l,r);}
    else{
        change_fz(lc,l,mid);
        change_fz(rc,mid+1,r);
    }
    tr[now].mx=max(tr[lc].mx,tr[rc].mx);
    tr[now].mn=min(tr[lc].mn,tr[rc].mn);
    tr[now].sum=tr[lc].sum+tr[rc].sum;
} 
int findmax(int now,int l,int r)
{
    if(tr[now].l==l && tr[now].r==r){ return tr[now].mx;}
    if(tr[now].gg) fz(now);
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid) return findmax(lc,l,r);
    else if(mid+1<=l) return findmax(rc,l,r);
    else return max(findmax(lc,l,mid),findmax(rc,mid+1,r));
}
int findmin(int now,int l,int r)
{
    if(tr[now].l==l && tr[now].r==r){ return tr[now].mn;}
    if(tr[now].gg) fz(now);
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid) return findmin(lc,l,r);
    else if(mid+1<=l) return findmin(rc,l,r);
    else return min(findmin(lc,l,mid),findmin(rc,mid+1,r));
}
int findsum(int now,int l,int r)
{
    if(tr[now].l==l && tr[now].r==r){ return tr[now].sum;}
    if(tr[now].gg) fz(now);
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid) return findsum(lc,l,r);
    else if(mid+1<=l) return findsum(rc,l,r);
    else return findsum(lc,l,mid)+findsum(rc,mid+1,r);
}
int solve_max(int x,int y)
{
    int tx=top[x],ty=top[y];
    int ans=-99999999;
    while(tx!=ty)
    {
        if(dep[tx]>dep[ty])
        {
            swap(x,y);
            swap(tx,ty);
        }
        ans=max(ans,findmax(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,findmax(1,ys[son[x]],ys[y]));
    }
}
int solve_min(int x,int y)
{
    int tx=top[x],ty=top[y];
    int ans=99999999;
    while(tx!=ty)
    {
        if(dep[tx]>dep[ty])
        {
            swap(x,y);
            swap(tx,ty);
        }
        ans=min(ans,findmin(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,findmin(1,ys[son[x]],ys[y]));
    }
}
int solve_sum(int x,int y)
{
    int tx=top[x],ty=top[y];
    int ans=0;
    while(tx!=ty)
    {
        if(dep[tx]>dep[ty])
        {
            swap(x,y);
            swap(tx,ty);
        }
        ans+=findsum(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);
        ans+=findsum(1,ys[son[x]],ys[y]);
        return ans;
    }
}
void solve_fz(int x,int y)
{
    int tx=top[x],ty=top[y];
    while(tx!=ty)
    {
        if(dep[tx]>dep[ty])
        {
            swap(x,y);
            swap(tx,ty);
        }
        change_fz(1,ys[ty],ys[y]);
        y=fa[ty],ty=top[y];
    }
    if(x==y) return ;
    else
    {
        if(dep[x]>dep[y]) swap(x,y);
        change_fz(1,ys[son[x]],ys[y]);
    }
}
int main()
{
//  freopen("travel.in","r",stdin);
//  freopen("travel.out","w",stdout);
    int n;scanf("%d",&n);
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<n;i++)
    {
        int x,y,c;
        scanf("%d%d%d",&x,&y,&c);x++;y++;
        ins(x,y,c);
        ins(y,x,c);
    }
    fa[1]=0;dep[1]=1;
    pre_tree_node(1);
    z=0; pre_tree_edge(1,1);
    trlen=0; bt(1,z);
    for(int i=1;i<=len;i+=2)
    {
        int x=a[i].x,y=a[i].y,c=a[i].c,id;
        if(dep[x]>dep[y]) id=x;
        else id=y;
        change(1,ys[id],c);
    }
    int m;scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        char ss[10]; scanf("%s",ss+1);
        int u,v;scanf("%d%d",&u,&v);
        if(ss[1]=='C')
        {
            int x=a[u*2-1].x,y=a[u*2-1].y,id;
            if(dep[x]>dep[y]) id=x;
            else id=y;
            change(1,ys[id],v);
        }
        else if(ss[1]=='N') {u++,v++;solve_fz(u,v);}
        else if(ss[1]=='S') {u++,v++;printf("%d\n",solve_sum(u,v));}
        else if(ss[2]=='A') {u++,v++;printf("%d\n",solve_max(u,v));}
        else if(ss[2]=='I') {u++,v++;printf("%d\n",solve_min(u,v));}
    }
    return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值