BZOJ[2157]旅游 树链剖分+线段树

21 篇文章 0 订阅
9 篇文章 0 订阅

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=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),输出答案。

Sample Input

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
Sample Output

3
2
1
-1
5
3
HINT

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

树剖模板题啊..
这道题给的是边权,只要把它放在他下面的点上就好了
区间相反数就yy一下就可以了,蒟蒻卡在了标记下传上Orz
注意当两个点爬到一个链上时不应该去上面的点的权值,因为这样会多算上面的那条边
可指针的初始值不是NULL吗???

代码如下:

#include<algorithm>
#include<ctype.h>
#include<cstdio>
#define INF 2147483647
#define N 20050
using namespace std;
inline int read(){
    int x=0,f=1;char c;
    do {c=getchar();if(c=='-') f=-1;} while(!isdigit(c));
    do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));
    return x*f;
}
int n,m,topp,x,y,k,T;
int fa[N],son[N],size[N],dep[N],fir[N],w[N];
int top[N],tree[N],pre[N];
char c[13];
struct Edge{
    int to,nex,k;
    Edge(int _=0,int __=0,int ___=0):to(_),nex(__),k(___){}
}nex[N*2];
struct Edge1{
    int x,y,k;
    Edge1(int _=0,int __=0,int ___=0):x(_),y(__),k(___){}
}s[N];//s数组储存输入的每条边
inline void add(int x,int y,int k){
    nex[++topp]=Edge(y,fir[x],k);
    fir[x]=topp;
}
void dfs1(int x,int Dep,int Fa){
    fa[x]=Fa;dep[x]=Dep;
    size[x]=1;
    for(int i=fir[x];i;i=nex[i].nex){
        if(nex[i].to==Fa) continue;
        dfs1(nex[i].to,Dep+1,x);
        w[nex[i].to]=nex[i].k;
        if(size[nex[i].to]>size[son[x]]) son[x]=nex[i].to;
    }
}
void dfs2(int x,int Top){
    tree[x]=++T;pre[T]=x;top[x]=Top;
    if(!son[x]) return;
    dfs2(son[x],Top);
    for(int i=fir[x];i;i=nex[i].nex){
        if(nex[i].to==fa[x] || nex[i].to==son[x]) continue;
        dfs2(nex[i].to,nex[i].to);
    }
}
struct Seg{
    int l,r,b;
    int minn,maxx,sum;
    Seg *ls,*rs;
    Seg(){l=r=b=minn=maxx=sum=0;ls=rs=NULL;}//不初始化指针会崩溃的啊啊啊啊啊啊
}root;
inline void Update(Seg *k){
    if(k->l==k->r) return;
    k->minn=min(k->ls->minn,k->rs->minn);
    k->maxx=max(k->ls->maxx,k->rs->maxx);
    k->sum=k->ls->sum+k->rs->sum;
}
inline void Pushdown(Seg *k){
    if(!k->b) return;
    if(k->ls!=NULL && !(k->ls->l==k->ls->r && k->ls->l==1)){
        swap(k->ls->minn,k->ls->maxx);
        k->ls->minn=-k->ls->minn;k->ls->maxx=-k->ls->maxx;
        k->ls->sum=-k->ls->sum;
        k->ls->b+=1;
        k->ls->b%=2;
    }
    if(k->rs!=NULL && !(k->rs->l==k->rs->r && k->rs->l==1)){
        swap(k->rs->minn,k->rs->maxx);
        k->rs->minn=-k->rs->minn;k->rs->maxx=-k->rs->maxx;
        k->rs->sum=-k->rs->sum;
        k->rs->b+=1;
        k->rs->b%=2;
    }
    k->b=0;
}
void maketree(int l,int r,Seg *k){
    k->l=l;k->r=r;k->b=0;
    if(l==r){
        k->minn=k->maxx=k->sum=w[pre[l]];
        return;
    }
    k->ls=new Seg;k->rs=new Seg;
    int mid=l+r>>1;
    maketree(l,mid,k->ls);maketree(mid+1,r,k->rs);
    Update(k);
}
int Query_Sum(int x,int y,Seg *k){
    if(k->l>=x && k->r<=y){
        return k->sum;
    }
    int mid=k->l+k->r>>1,tmp=0;
    Pushdown(k);Update(k);
    if(mid>=y) tmp=Query_Sum(x,y,k->ls);
    else if(mid<x) tmp=Query_Sum(x,y,k->rs);
    else tmp=Query_Sum(x,y,k->ls)+Query_Sum(x,y,k->rs);
    Pushdown(k);Update(k);
    return tmp;
}
int Query_Min(int x,int y,Seg *k){
    if(k->l>=x && k->r<=y){
        return k->minn;
    }
    int mid=k->l+k->r>>1,tmp=INF;
    Pushdown(k);Update(k);
    if(mid>=y) tmp=Query_Min(x,y,k->ls);
    else if(mid<x) tmp=Query_Min(x,y,k->rs);
    else tmp=min(Query_Min(x,y,k->ls),Query_Min(x,y,k->rs));
    Pushdown(k);Update(k);
    return tmp;
}
int Query_Max(int x,int y,Seg *k){
    if(k->l>=x && k->r<=y){
        return k->maxx;
    }
    int mid=k->l+k->r>>1,tmp=-INF;
    Pushdown(k);Update(k);
    if(mid>=y) tmp=Query_Max(x,y,k->ls);
    else if(mid<x) tmp=Query_Max(x,y,k->rs);
    else tmp=max(Query_Max(x,y,k->ls),Query_Max(x,y,k->rs));
    Pushdown(k);Update(k);
    return tmp;
}
void Modify(int x,int v,Seg *k){
    if(k->l==k->r){
        k->sum=k->maxx=k->minn=v;
        return;
    }
    int mid=k->l+k->r>>1;
    Pushdown(k);Update(k);
    if(x<=mid) Modify(x,v,k->ls);
    else if(x>mid) Modify(x,v,k->rs);
    Pushdown(k);Update(k);
}
void Opposite(int x,int y,Seg *k){
    if(k->l>=x && k->r<=y){
        Pushdown(k);Update(k);
        k->b=1;
        swap(k->maxx,k->minn);
        k->minn=-k->minn;k->maxx=-k->maxx;k->sum=-k->sum;
        return;
    }
    int mid=k->l+k->r>>1;
    Pushdown(k);Update(k);
    if(mid>=y) Opposite(x,y,k->ls);
    else if(mid<x) Opposite(x,y,k->rs);
    else Opposite(x,y,k->ls),Opposite(x,y,k->rs);
    Pushdown(k);Update(k);
}
inline void Defend(int &x,int &y){
    if(dep[top[x]]<dep[top[y]]) swap(x,y);
}
inline void Opposite_Tree(int x,int y){
    while(top[x]!=top[y]){
        Defend(x,y);
        Opposite(tree[top[x]],tree[x],&root);
        x=fa[top[x]];
    }
    if(x==y) return;
    if(tree[x]>tree[y]) swap(x,y);
    Opposite(tree[x]+1,tree[y],&root);
}
inline int Sum_Tree(int x,int y){
    int sum=0;
    while(top[x]!=top[y]){
        Defend(x,y);
        sum+=Query_Sum(tree[top[x]],tree[x],&root);
        x=fa[top[x]];
    }
    if(x==y) return sum;
    if(tree[x]>tree[y]) swap(x,y);
    sum+=Query_Sum(tree[x]+1,tree[y],&root);
    return sum;
}
inline int Min_Tree(int x,int y){
    int minn=INF;
    while(top[x]!=top[y]){
        Defend(x,y);
        minn=min(Query_Min(tree[top[x]],tree[x],&root),minn);
        x=fa[top[x]];
    }
    if(x==y) return minn;
    if(tree[x]>tree[y]) swap(x,y);
    minn=min(Query_Min(tree[x]+1,tree[y],&root),minn);
    return minn;
}
inline int Max_Tree(int x,int y){
    int maxx=-INF;
    while(top[x]!=top[y]){
        Defend(x,y);
        maxx=max(Query_Max(tree[top[x]],tree[x],&root),maxx);
        x=fa[top[x]];
    }
    if(x==y) return maxx;//这个地方特判一下
    if(tree[x]>tree[y]) swap(x,y);
    maxx=max(Query_Max(tree[x]+1,tree[y],&root),maxx);
    return maxx;
}
void print(Seg *k){
    if(k->ls!=NULL) print(k->ls);if(k->rs!=NULL) print(k->rs);
    printf("l:%d r:%d    max:%d  min:%d  sum:%d  b:%d\n",k->l,k->r,k->maxx,k->minn,k->sum,k->b);
}
void Debug(){//调试函数Orz
    printf("\n\nTree Pou:\n");
    for(int i=1;i<=n;i++){
        printf("id:%d   tree:%d  fa:%d  dep:%d  son:%d  top:%d\n",i,tree[i],fa[i],dep[i],son[i],top[i]);
    }
    printf("\n\nSegment Tree:\n");
    print(&root);
}
int main(){
    n=read();
    for(int i=1;i<n;i++){
        x=read()+1;y=read()+1;k=read();
        s[i]=Edge1(x,y,k);
        add(x,y,k);add(y,x,k);
    }
    m=read();
    dfs1(1,1,0);dfs2(1,1);
    maketree(1,n,&root);
    for(int i=1;i<=m;i++){
        scanf("%s",c+1);
        x=read();y=read();
        if(c[1]=='C') Modify(tree[s[x].y],y,&root);
        else if(c[1]=='N') Opposite_Tree(++x,++y);
        else if(c[1]=='S') printf("%d\n",Sum_Tree(++x,++y));
        else if(c[2]=='I') printf("%d\n",Min_Tree(++x,++y));
        else if(c[2]=='A') printf("%d\n",Max_Tree(++x,++y));
    }
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值