【国家集训队】旅游 题解(树剖基础)

题目描述

Ray 乐忠于旅游,这次他来到了T 城。T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接。为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径。换句话说, T 城中只有N − 1 座桥。

Ray 发现,有些桥上可以看到美丽的景色,让人心情愉悦,但有些桥狭窄泥泞,令人烦躁。于是,他给每座桥定义一个愉悦度w,也就是说,Ray 经过这座桥会增加w 的愉悦度,这或许是正的也可能是负的。有时,Ray 看待同一座桥的心情也会发生改变。

现在,Ray 想让你帮他计算从u 景点到v 景点能获得的总愉悦度。有时,他还想知道某段路上最美丽的桥所提供的最大愉悦度,或是某段路上最糟糕的一座桥提供的最低愉悦度。

输入输出格式

输入格式:

输入的第一行包含一个整数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。

输出格式:

对于每一个询问(操作S、MAX 和MIN),输出答案。

样例输入:

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

样例输出:

3
2
1
-1
5
3

解:

  本题题意比较明确,就是树链剖分,需要维护区间和,区间最大值,区间最小值,以及单点修改,区间乘以-1.还有一点,本题的题目中要求的是边权,而树剖求的是点权,故我们需要边权转点权。查询时,注意不要查询到两点的LCA.

  区间标记下传的时候,注意是异或,不是单纯累加;修改时,把区间的最大值用区间的最小值的相反数代替,最小值同理。修改完成。

  本题码量比较大,各位可以先尝试一下QTree1,即边权转点权+单点修改+维护区间MAX.

  本题的n可以稍微开大一点,注意线段树四倍空间,前向星两倍空间,初始时不要忘记给dep数组初始化。

  查询最大/最小/区间和的时候,我们可以压缩为一个函数(即代码中的query,多了一个参数.),可以减少码量。

  注意,不查询lca,即跳链完成后查询id[x]+1即可.例如:modify(id[x]+1,id[y],rt).

  记住建双向边,不初始化会T的很惨(像我一样).

  Code:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#define MAXN 200010
#define inf 0x7fffffff
using namespace std;
struct node{
    int nxt,to;
}e[MAXN<<1];
int head[MAXN],son[MAXN],top[MAXN],dep[MAXN];
int n,m,siz[MAXN],f[MAXN],a[MAXN],val[MAXN];
int cnt,tot,id[MAXN],rk[MAXN],dt,rt;
inline void swap(int &x,int &y){x^=y^=x^=y;}
char s[10];
inline int max_(int a,int b){return a>b?a:b;}
inline int min_(int a,int b){return a<b?a:b;}
inline int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')w=-1;
        ch=getchar();
    }while(ch>='0'&&ch<='9'){
        s=(s<<1)+(s<<3)+(ch^48);
        ch=getchar();
    }return s*w;
}
struct Node{
    int ls,rs,sum,tag,maxn,minn,l,r;
}tr[MAXN<<2];
inline void add(int x,int y,int w){
    e[++tot].to=y;
    e[tot].nxt=head[x];
    head[x]=tot;
    a[tot]=w;
}
void dfs1(int u){
    siz[u]=1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==f[u])continue;
        f[v]=u;
        val[v]=a[i];
        dep[v]=dep[u]+1;
        dfs1(v);
        siz[u]=siz[v]+1;
        if(siz[son[u]]<siz[v])son[u]=v;
    }
}void dfs2(int u,int t){
    top[u]=t;
    rk[id[u]=++dt]=u;
    if(!son[u])return;
    dfs2(son[u],t);
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v!=f[u]&&v!=son[u])dfs2(v,v);
    }
}
#define lc tr[x].ls
#define rc tr[x].rs
inline void pushup(int x){
    tr[x].sum=tr[lc].sum+tr[rc].sum;
    tr[x].maxn=max_(tr[lc].maxn,tr[rc].maxn);
    tr[x].minn=min_(tr[lc].minn,tr[rc].minn);
}
inline void pushdown(int x){
    if(tr[x].tag){
        tr[lc].sum=-tr[lc].sum,tr[lc].tag^=1;
        tr[rc].sum=-tr[rc].sum,tr[rc].tag^=1;
        int x1=tr[lc].maxn,y1=tr[lc].minn;
        int x2=tr[rc].maxn,y2=tr[rc].minn;
        tr[lc].maxn=-y1,tr[lc].minn=-x1;
        tr[rc].maxn=-y2,tr[rc].minn=-x2;
        tr[x].tag=0;
    }
}
void build(int li,int ri,int &x){
    x=++cnt;
    tr[x].l=li;tr[x].r=ri;
    if(li==ri){
        tr[x].minn=tr[x].maxn=tr[x].sum=val[rk[li]];
        return;
    }int mid=(li+ri)>>1;
    build(li,mid,lc);
    build(mid+1,ri,rc);
    pushup(x);
}
void change(int x,int val,int cur){
    if(tr[x].l==tr[x].r){
        tr[x].sum=tr[x].maxn=tr[x].minn=val;
        return;
    }pushdown(x);
    int mid=(tr[x].l+tr[x].r)>>1;
    if(cur<=mid)change(lc,val,cur);
    else change(rc,val,cur);
    pushup(x);
}
void modify(int li,int ri,int x){
    if(tr[x].l>=li&&tr[x].r<=ri){
        tr[x].sum=-tr[x].sum,tr[x].tag^=1;
        int x1=tr[x].maxn,y1=tr[x].minn;
        tr[x].maxn=-y1,tr[x].minn=-x1;
        return;
    }pushdown(x);
    int mid=(tr[x].l+tr[x].r)>>1;
    if(li<=mid)modify(li,ri,lc);
    if(mid<ri)modify(li,ri,rc);
    pushup(x);
}
int query_s(int li,int ri,int x){
    if(tr[x].l>ri||tr[x].r<li)return 0;
    if(tr[x].l>=li&&tr[x].r<=ri)return tr[x].sum;
    pushdown(x);
    int mid=(tr[x].l+tr[x].r)>>1,ans=0;
    ans=query_s(li,ri,lc)+query_s(li,ri,rc);
    return ans;
}
int query_x(int li,int ri,int x){
    if(tr[x].l>=li&&tr[x].r<=ri)return tr[x].maxn;
    pushdown(x);
    int mid=(tr[x].l+tr[x].r)>>1,ans=-inf;
    if(li<=mid)ans=max_(ans,query_x(li,ri,lc));
    if(mid<ri)ans=max_(ans,query_x(li,ri,rc));
    return ans;
}
int query_n(int li,int ri,int x){
    if(tr[x].l>=li&&tr[x].r<=ri){return tr[x].minn;}
    pushdown(x);int mid=(tr[x].l+tr[x].r)>>1,ans=inf;
    if(li<=mid)ans=min_(ans,query_n(li,ri,lc));
    if(mid<ri)ans=min_(ans,query_n(li,ri,rc));
    return ans;
}
void Segment_change(int x,int y){
    int fx=top[x],fy=top[y];
    while(fx!=fy){
        if(dep[fx]<dep[fy])swap(x,y),swap(fx,fy);
        modify(id[fx],id[x],rt);
        x=f[fx],fx=top[x];
    }if(id[x]>id[y])swap(x,y);
    modify(id[x]+1,id[y],rt);
}
int query(int x,int y,int ck){//ck 0sum 1max 2min
    int fx=top[x],fy=top[y],ans;
    if(ck==0)ans=0;else if(ck==1)ans=-inf;else ans=inf;
    while(fx!=fy){
        if(dep[fx]<dep[fy])swap(x,y),swap(fx,fy);
        if(ck==0)ans+=query_s(id[fx],id[x],rt);
        else if(ck==1)ans=max_(ans,query_x(id[fx],id[x],rt));
        else if(ck==2)ans=min_(ans,query_n(id[fx],id[x],rt));
        x=f[fx],fx=top[x];
    }if(id[x]>id[y])swap(x,y);
    if(ck==0)ans+=query_s(id[x]+1,id[y],rt);
    else if(ck==1)ans=max_(ans,query_x(id[x]+1,id[y],rt));
    else if(ck==2)ans=min_(ans,query_n(id[x]+1,id[y],rt));
    return ans;
}
int main(){dep[0]=1;
    n=read();
    for(register int i=1;i<n;++i){
        int u=read()+1,v=read()+1,w=read();
        add(u,v,w);add(v,u,w);
    }m=read();
    dfs1(1);
    dfs2(1,1);
    build(1,n,rt);
    for(register int i=1;i<=m;++i){
        scanf("%s",s);
        int x=read()+1,y=read()+1;
        if(s[0]=='C')change(rt,y-1,id[x]);
        else if(s[0]=='N')Segment_change(x,y);
        else if(s[0]=='S')printf("%d\n",query(x,y,0));
        else if(s[1]=='A')printf("%d\n",query(x,y,1));
        else if(s[1]=='I')printf("%d\n",query(x,y,2));
    }
    return 0;
}

感谢 fengsongquan dalao的指导.

猜你喜欢

转载自www.cnblogs.com/h-lka/p/10798347.html
今日推荐