BZOJ2157 旅游

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),输出答案。
(样例略)
HINT

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

树链剖分裸题。线段树代码量巨大,一定要沉得住气。
注意,反转一个节点要将其标记异或1,而不是直接对其赋值。因为这个WA了很久。
自己的代码:

#include<cstdio> 
#define gm 20001 
using namespace std; 
int n,m; 
struct e 
{ 
    int t,v; 
    e *n; 
    e (int t,e *n,int v):t(t),n(n),v(v){} 
}*b[gm]={}; 
inline int max(int a,int b){return a<b?b:a;} 
inline int min(int a,int b){return a<b?a:b;} 
#define swap(a,b) a^=b^=a^=b 
#define link(x,y,z) b[x]=new e(y,b[x],z);b[y]=new e(x,b[y],z) 
#define along(x) for(e *i=b[x];i;i=i->n) 
#define getm int mid=(l+r)/2,p=o<<1,q=(o<<1)+1 
//begin 
int size[gm],fat[gm],hev[gm],dpt[gm],ord[gm],top[gm],now=0,q1[gm],q2[gm],qv[gm];
void first(int x) 
{ 
    size[x]=1; 
    dpt[x]=dpt[fat[x]]+1; 
    int y; 
    along(x) 
    { 
        y=i->t; 
        if(fat[x]==y) continue; 
        fat[y]=x; 
        first(y); 
        size[x]+=size[y]; 
        if(size[y]>size[hev[x]]) 
        hev[x]=y; 
    } 
} 
void second(int x) 
{ 
    top[x]=x==hev[fat[x]]?top[fat[x]]:x; 
    ord[x]=++now; 
    if(hev[x]) second(hev[x]); 
    int y; 
    along(x) 
    { 
        y=i->t; 
        if(fat[x]==y||hev[x]==y) continue; 
        second(y); 
    } 
} 
//end 
//------------------------------------------- 
//begin 
int sum[gm*4],maxx[gm*4],minn[gm*4]; 
bool rev[gm*4]; 
int x,y,v,ans; 
void change(int l,int r,int o) 
{ 
    if(l==r) 
    { 
        sum[o]=maxx[o]=minn[o]=v; 
        rev[o]=0; 
        return; 
    } 
    getm; 
    if(rev[o]) v=-v;
    if(x<=mid) change(l,mid,p); 
    else change(mid+1,r,q); 
    sum[o]=sum[p]+sum[q]; 
    maxx[o]=max(maxx[p],maxx[q]); 
    minn[o]=min(minn[p],minn[q]);
    if(rev[o])
    {
        sum[o]=-sum[o]; 
        int a=maxx[o]; 
        maxx[o]=-minn[o]; 
        minn[o]=-a; 
    }
} 
inline void change(int pos,int val) 
{ 
    x=pos;v=val; 
    change(1,n,1); 
} 
void seija(int l,int r,int o) 
{ 
    if(x<=l&&r<=y) 
    { 
        rev[o]^=1; 
        sum[o]=-sum[o]; 
        int a=maxx[o]; 
        maxx[o]=-minn[o]; 
        minn[o]=-a; 
        return; 
    }
    getm;
    if(x<=mid) seija(l,mid,p); 
    if(mid<y) seija(mid+1,r,q); 
    sum[o]=sum[p]+sum[q]; 
    maxx[o]=max(maxx[p],maxx[q]); 
    minn[o]=min(minn[p],minn[q]);
    if(rev[o])
    {
        sum[o]=-sum[o]; 
        int a=maxx[o]; 
        maxx[o]=-minn[o]; 
        minn[o]=-a; 
    } 
} 
inline void seija(int ll,int rr) 
{ 
    x=ll;y=rr; 
    seija(1,n,1); 
} 
void getsum(int l,int r,int o,bool nz) 
{ 
    if(x<=l&&r<=y) 
    { 
        ans+=nz?-sum[o]:sum[o]; 
        return; 
    } 
    getm; 
    if(rev[o]) nz^=1;
    if(x<=mid) getsum(l,mid,p,nz); 
    if(mid<y) getsum(mid+1,r,q,nz); 
} 
inline int getsum(int ll,int rr) 
{ 
    x=ll;y=rr;ans=0; 
    getsum(1,n,1,0); 
    return ans; 
} 
void getmax(int l,int r,int o,bool nz) 
{ 
    if(x<=l&&r<=y) 
    { 
        if(!nz) ans=max(ans,maxx[o]); 
        else ans=max(ans,-minn[o]);
        return; 
    } 
    getm;
    if(rev[o]) nz^=1; 
    if(x<=mid) getmax(l,mid,p,nz); 
    if(mid<y) getmax(mid+1,r,q,nz); 
} 
inline int getmax(int ll,int rr) 
{ 
    x=ll;y=rr;ans=-2000000000; 
    getmax(1,n,1,0); 
    return ans; 
} 
void getmin(int l,int r,int o,int nz) 
{ 
    if(x<=l&&r<=y) 
    { 
        if(!nz) ans=min(ans,minn[o]); 
        else ans=min(ans,-maxx[o]);
        return; 
    } 
    getm; 
    if(rev[o]) nz^=1;
    if(x<=mid) getmin(l,mid,p,nz); 
    if(mid<y) getmin(mid+1,r,q,nz); 
} 
inline int getmin(int ll,int rr) 
{ 
    x=ll;y=rr;ans=2000000000; 
    getmin(1,n,1,0); 
    return ans; 
} 
//end 
//------------------------------- 
//begin 
int work_s(int beg,int end) 
{ 
    int all=0; 
    while(top[beg]!=top[end]) 
    { 
        if(dpt[top[beg]]<dpt[top[end]]) 
        swap(beg,end); 
        all+=getsum(ord[top[beg]],ord[beg]); 
        beg=fat[top[beg]]; 
    } 
    if(beg==end) return all; 
    if(dpt[end]<dpt[beg]) 
    swap(beg,end); 
    all+=getsum(ord[beg]+1,ord[end]); 
    return all; 
} 
int work_a(int beg,int end) 
{ 
    int all=-2000000000; 
    while(top[beg]!=top[end]) 
    { 
        if(dpt[top[beg]]<dpt[top[end]]) 
        swap(beg,end); 
        all=max(all,getmax(ord[top[beg]],ord[beg])); 
        beg=fat[top[beg]]; 
    } 
    if(beg==end) return all; 
    if(dpt[end]<dpt[beg]) 
    swap(beg,end); 
    all=max(all,getmax(ord[beg]+1,ord[end])); 
    return all; 
} 
int work_i(int beg,int end) 
{ 
    int all=2000000000; 
    while(top[beg]!=top[end]) 
    { 
        if(dpt[top[beg]]<dpt[top[end]]) 
        swap(beg,end); 
        all=min(all,getmin(ord[top[beg]],ord[beg])); 
        beg=fat[top[beg]]; 
    } 
    if(beg==end) return all; 
    if(dpt[end]<dpt[beg]) 
    swap(beg,end); 
    all=min(all,getmin(ord[beg]+1,ord[end])); 
    return all; 
} 
void work_r(int beg,int end) 
{ 
    while(top[beg]!=top[end]) 
    { 
        if(dpt[top[beg]]<dpt[top[end]]) 
        swap(beg,end); 
        seija(ord[top[beg]],ord[beg]); 
        beg=fat[top[beg]]; 
    }
    if(beg==end) return; 
    if(dpt[end]<dpt[beg]) 
    swap(beg,end); 
    seija(ord[beg]+1,ord[end]); 
} 
inline void work_c(int no,int val)
{
    if(fat[q1[no]]==q2[no]) change(ord[q1[no]],val);
    else change(ord[q2[no]],val);
}
//end 
//-------------------------------- 
//begin 
int main() 
{
    scanf("%d",&n); 
    int s2,s3,s4; 
    for(int i=1;i<n;i++) 
    { 
        scanf("%d%d%d",&s2,&s3,&s4); 
        link(s2+1,s3+1,s4); 
        q1[i]=s2+1; 
        q2[i]=s3+1; 
        qv[i]=s4; 
    } 
    first(1); 
    second(1); 
    for(int i=1;i<n;i++) 
    work_c(i,qv[i]);
    char s1[5]; 
    scanf("%d",&m); 
    for(int i=1;i<=m;i++) 
    { 
        scanf("%s%d%d",s1,&s2,&s3); 
        if(s1[0]=='C') 
        work_c(s2,s3);
        else if(s1[0]=='N') 
        work_r(s2+1,s3+1); 
        else if(s1[0]=='S') 
        printf("%d\n",work_s(s2+1,s3+1)); 
        else if(s1[1]=='A') 
        printf("%d\n",work_a(s2+1,s3+1)); 
        else if(s1[1]=='I') 
        printf("%d\n",work_i(s2+1,s3+1)); 
    } 
    return 0; 
} 
//end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值