BZOJ2157: 旅游

【传送门:BZOJ3676


简要题意:

  给出一棵树,树上的边有权值(可正可负),对这棵树有5种操作:

  1.SUM x y求出x点到y点所经过的边权和

  2.MAX x y求出x点到y点所经过的边的最大边权

  3.MIN x y求出x点到y点所经过的边的最小边权

  4.C x y将输入的第x条边的边权改为y

  5.N x y将x点到y点所经过的边的边权全部变成自己的相反数


题解:

  很显然,在树上求路径特征值,用树链剖分

  对于边权,就把边权变为这条边深度最深的点的点权,然后在求特征值的时候注意一下就行了

  关键是相反数问题,注意:假设一段区间的和为s,最大值为mx,最小值为mn,那么取相反数后,这段区间的和为-s,最大值为-mn,最小值为-mx

  然后因为修改的是区间,所以要用lazy标记来继承状态

  因为原题的点编号为0到n-1,有点恶心,所以把编号改为1到n

  然而我,就因为在一个操作中没有x++,y++,卡了一个中午


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
struct node
{
    int x,y,next;
}a[41000];int len,last[21000];
struct trnode
{
    int l,r,lc,rc,mn,mx,s;
    int lazy;
    trnode()
    {
        lazy=0;
    }
}tr[41000];int trlen;
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
void update(int x)
{
    int lc=tr[x].lc,rc=tr[x].rc;
    int mn,mx;
    if(lc!=-1)
    {
        mn=tr[lc].mn;mx=tr[lc].mx;
        tr[lc].mn=-mx;tr[lc].mx=-mn;
        tr[lc].s=-tr[lc].s;
        tr[lc].lazy^=1;
    }
    if(rc!=-1)
    {
        mn=tr[rc].mn;mx=tr[rc].mx;
        tr[rc].mn=-mx;tr[rc].mx=-mn;
        tr[rc].s=-tr[rc].s;
        tr[rc].lazy^=1;
    }
    tr[x].lazy=0;
}
void follow(int x)
{
    int lc=tr[x].lc,rc=tr[x].rc;
    tr[x].s=tr[lc].s+tr[rc].s;
    tr[x].mx=max(tr[lc].mx,tr[rc].mx);
    tr[x].mn=min(tr[lc].mn,tr[rc].mn);
}
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].mn=tr[now].mx=0;tr[now].s=0;
    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);
    }
}
int tot[21000],fa[21000],dep[21000],son[21000];
void pre_tree_node(int x)
{
    tot[x]=1;son[x]=0;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa[x])
        {
            dep[y]=dep[x]+1;
            fa[y]=x;
            pre_tree_node(y);
            tot[x]+=tot[y];
            if(tot[y]>tot[son[x]]) son[x]=y;
        }
    }
}
int ys[21000],z,top[21000];
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);
    }
}
void add(int now,int x,int c)
{
    if(tr[now].l==tr[now].r)
    {
        tr[now].s=c;
        tr[now].mx=tr[now].mn=tr[now].s;
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(tr[now].lazy==1) update(now);
    if(x<=mid) add(lc,x,c);
    else add(rc,x,c);
    follow(now);
}
void xf(int now,int l,int r)
{
    if(tr[now].l==l&&tr[now].r==r)
    {
        tr[now].lazy^=1;
        int mn=tr[now].mn,mx=tr[now].mx;
        tr[now].mx=-mn;tr[now].mn=-mx;
        tr[now].s=-tr[now].s;
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(tr[now].lazy==1) update(now);
    if(r<=mid) xf(lc,l,r);
    else if(l>mid) xf(rc,l,r);
    else
    {
        xf(lc,l,mid);xf(rc,mid+1,r);
    }
    follow(now);
}
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);
        }
        xf(1,ys[ty],ys[y]);
        y=fa[ty];ty=top[y];
    }
    if(x!=y)
    {
        if(dep[x]>dep[y]) swap(x,y);
        xf(1,ys[son[x]],ys[y]);
    }
}
int getsum(int now,int l,int r)
{
    if(tr[now].l==l&&tr[now].r==r) return tr[now].s;
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(tr[now].lazy==1) update(now);
    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 findmax(int now,int l,int r)
{
    if(tr[now].l==l&&tr[now].r==r) return tr[now].mx;
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(tr[now].lazy==1) update(now);
    if(r<=mid) return findmax(lc,l,r);
    else if(l>mid) 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;
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(tr[now].lazy==1) update(now);
    if(r<=mid) return findmin(lc,l,r);
    else if(l>mid) return findmin(rc,l,r);
    else return min(findmin(lc,l,mid),findmin(rc,mid+1,r));
}
int solve(int x,int y,int t)
{
    if(t==1)
    {
        int ans=0,tx=top[x],ty=top[y];
        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]);
        }
    }
    else if(t==2)
    {
        int ans=-999999999,tx=top[x],ty=top[y];
        while(tx!=ty)
        {
            if(dep[tx]>dep[ty])
            {
                swap(tx,ty);
                swap(x,y);
            }
            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]));
        }
    }
    else if(t==3)
    {
        int ans=999999999,tx=top[x],ty=top[y];
        while(tx!=ty)
        {
            if(dep[tx]>dep[ty])
            {
                swap(tx,ty);
                swap(x,y);
            }
            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]));
        }
    }
}
struct enode
{
    int x,y,d;
}e[21000];
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int n;
    scanf("%d",&n);
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<n;i++)
    {
        scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].d);
        e[i].x++;e[i].y++;
        ins(e[i].x,e[i].y);ins(e[i].y,e[i].x);
    }
    dep[1]=0;fa[1]=0;pre_tree_node(1);
    z=0;pre_tree_edge(1,1);
    trlen=0;bt(1,z);
    for(int i=1;i<n;i++) if(dep[e[i].x]>dep[e[i].y]) swap(e[i].x,e[i].y);
    for(int i=1;i<n;i++) add(1,ys[e[i].y],e[i].d);
    int m;
    scanf("%d",&m);
    char st[5];
    for(int i=1;i<=m;i++)
    {
        scanf("%s",st+1);
        int x,y;
        scanf("%d%d",&x,&y);
        if(st[1]=='C')
        {
            add(1,ys[e[x].y],y);
            continue;
        }
        x++;y++;
        if(st[1]=='N') change(x,y);
        if(st[1]=='S') printf("%d\n",solve(x,y,1));
        if(st[1]=='M'&&st[2]=='A') printf("%d\n",solve(x,y,2));
        if(st[1]=='M'&&st[2]=='I') printf("%d\n",solve(x,y,3));
    }
    return 0;
}

 

posted @ 2018-03-01 13:45  Star_Feel  阅读(155)  评论(0编辑  收藏  举报