bzoj2157: 旅游(树链剖分)

题目传送门
呵呵呵。

解法:
没学过树剖看这里
很水很水的树剖?
整段取反就打个lazy嘛。

列举各种情况。
就会发现,取反时:
最大值等于原来最小值取反,最小值等于原来最大值取反。

其他维护最大值最小值和就没什么了吧。

代码实现:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
struct node {int x,y,next;}a[51000];int len,last[21000];
void ins(int x,int y) {len++;a[len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len;}
int n,fa[21000],dep[21000],tot[21000],son[21000];
void 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]) {
            dep[y]=dep[x]+1;fa[y]=x;pre_tree_node(y);
            if(tot[y]>tot[son[x]])son[x]=y;tot[x]+=tot[y];
        }
    }
}
int z,ys[21000],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(fa[x]!=y&&son[x]!=y)pre_tree_edge(y,y);}
}
struct trnode {int l,r,lc,rc,c,mn,mx,lazy;}tr[51000];int trlen;
void bt(int l,int r) {
    int now=++trlen;tr[now].l=l;tr[now].r=r;tr[now].c=tr[now].mx=tr[now].mn=0;tr[now].lc=tr[now].rc=-1;tr[now].lazy=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);}
}
void update(int now) {
    int lc=tr[now].lc,rc=tr[now].rc;tr[now].lazy=0;
    tr[lc].lazy^=1;tr[rc].lazy^=1;
    int t=tr[lc].mx;tr[lc].mx=tr[lc].mn*-1;tr[lc].mn=t*-1;
    t=tr[rc].mx;tr[rc].mx=tr[rc].mn*-1;tr[rc].mn=t*-1;
    tr[lc].c*=-1;tr[rc].c*=-1;
}
int find_sum(int now,int l,int r) {
    if(tr[now].lazy)update(now);
    if(tr[now].l==l&&tr[now].r==r)return tr[now].c;
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid)return find_sum(lc,l,r);else if(l>mid)return find_sum(rc,l,r);
    else return find_sum(lc,l,mid)+find_sum(rc,mid+1,r);
}
int find_max(int now,int l,int r) {
    if(tr[now].lazy)update(now);
    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(r<=mid)return find_max(lc,l,r);else if(l>mid)return find_max(rc,l,r);
    else return max(find_max(lc,l,mid),find_max(rc,mid+1,r));
}
int find_min(int now,int l,int r) {
    if(tr[now].lazy)update(now);
    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(r<=mid)return find_min(lc,l,r);else if(l>mid)return find_min(rc,l,r);
    else return min(find_min(lc,l,mid),find_min(rc,mid+1,r));
}
void change(int now,int x,int k) {
    if(tr[now].lazy)update(now);
    if(tr[now].l==tr[now].r) {tr[now].c=tr[now].mn=tr[now].mx=k;return ;}
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(x<=mid)change(lc,x,k);else change(rc,x,k);
    tr[now].mx=max(tr[lc].mx,tr[rc].mx);tr[now].mn=min(tr[lc].mn,tr[rc].mn);tr[now].c=tr[lc].c+tr[rc].c;
}
void qf(int now,int l,int r) {
    if(tr[now].l==l&&tr[now].r==r) {tr[now].lazy^=1;int t=tr[now].mx;tr[now].mx=tr[now].mn*-1;tr[now].mn=t*-1;tr[now].c*=-1;return ;}
    if(tr[now].lazy)update(now);int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid)qf(lc,l,r);else if(l>mid)qf(rc,l,r);
    else {qf(lc,l,mid),qf(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].c=tr[lc].c+tr[rc].c;
}
int solve_sum(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+=find_sum(1,ys[ty],ys[y]);y=fa[ty];ty=top[y];
    }
    if(x==y)return ans;
    if(dep[x]>dep[y])swap(x,y);return ans+find_sum(1,ys[son[x]],ys[y]);
}
const int inf=999999999;
int solve_max(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,find_max(1,ys[ty],ys[y]));y=fa[ty];ty=top[y];
    }
    if(x==y)return ans;
    if(dep[x]>dep[y])swap(x,y);return max(ans,find_max(1,ys[son[x]],ys[y]));
}
int solve_min(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,find_min(1,ys[ty],ys[y]));y=fa[ty];ty=top[y];
    }
    if(x==y)return ans;
    if(dep[x]>dep[y])swap(x,y);return min(ans,find_min(1,ys[son[x]],ys[y]));
}
void solve_qf(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);}
        qf(1,ys[ty],ys[y]);y=fa[ty];ty=top[y];
    }
    if(x==y)return ;
    if(dep[x]>dep[y])swap(x,y);qf(1,ys[son[x]],ys[y]);
}
struct edge {int x,y,c;}e[21000];
int main() {
    int m;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].c);e[i].x++;e[i].y++;ins(e[i].x,e[i].y);ins(e[i].y,e[i].x);}
    fa[1]=0;dep[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);change(1,ys[e[i].y],e[i].c);}
    scanf("%d",&m);
    for(int i=1;i<=m;i++) {
        char s[5];int x,y;scanf("%s%d%d",s+1,&x,&y);
        if(s[1]=='C')change(1,ys[e[x].y],y);
        else if(s[1]=='N')solve_qf(++x,++y);
        else if(s[1]=='S')printf("%d\n",solve_sum(++x,++y));
        else if(s[2]=='A')printf("%d\n",solve_max(++x,++y));
        else printf("%d\n",solve_min(++x,++y));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值