【国家集训队】旅游 题解(树剖基础)
作者:互联网
题目描述
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的指导.
标签:树剖,int,题解,tr,景点,ans,国家集训队,id,愉悦 来源: https://www.cnblogs.com/h-lka/p/10798347.html