树链剖分 月下毛景树
月下“毛景树”
题目描述
毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园。 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里。
爬啊爬
毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~ “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的。但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数:
- Change k w:将第k条树枝上毛毛果的个数改变为w个。
- Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。
- Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。 由于毛毛虫很贪,于是他会有如下询问:
- Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。
输入输出格式
输入格式:
第一行一个正整数N。
接下来N-1行,每行三个正整数Ui,Vi和Wi,第i+1行描述第i条树枝。表示第i条树枝连接节点Ui和节点Vi,树枝上有Wi个毛毛果。 接下来是操作和询问,以“Stop”结束。
输出格式:
对于毛毛虫的每个询问操作,输出一个答案。
三个小时做这一道题,却是因为一个变量名写错。
好吧,还是要总结的,不然也没有收获不是?
这是一道比较简单的树剖,可以说是裸题。
但也有以下几个问题需要注意。
1,题目中给出的是边权,那么考虑怎样才会计算到边权,因为每个点只有一个父亲,所以可以想到把每条边的边权转移到深度较大的点上,这也是一种边权转点权的常见套路,需要记住。
2,题目要求我们维护区间最大值,区间加和区间覆盖。
对于线段树的两种操作(推广到多个操作),一定要考虑操作的优先级。
一般的算术操作要推式子,这道题的区间覆盖显然不用推式子。
那么考虑如果当前线段树内的该节点有一个区间加的tag,那么当我们执行区间覆盖时,就一定要把区间加标记去掉,因为不可以让这段区间在区间覆盖之后再次因为之前的区间加标记改变,想一想其实很容易理解。
3,针对这道题的几个操作,我们发现在树剖的时候,因为我们每个点的点权其实是点向上的边的边权,所以就会发现,对于每次操作的X,Y两点,他们的LCA是一定不能参与到任何操作或者计算的,因为LCA的对应的边并不在X到Y的区间内,所以每次操作之前把LCA特殊处理一下,再在操作之后将LCA的数据维护一下即可。比较简单。
code:
#include<iostream>
#include<cstdio>
#define ls(o) o<<1
#define rs(o) o<<1|1
#define int long long
using namespace std;
const int wx=100017;
inline int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
return sum*f;
}
struct val_tree{
int l,r,ma,tag,ta;
#define ma(o) t[o].ma
#define ta(o) t[o].ta
#define tag(o) t[o].tag
}t[wx*4];
struct e{
int nxt,to,dis;
}edge[wx*2];
char opt[9];
int num,tot,n,x,y,z,k;
int head[wx],f[wx][23];
int a[wx],tid[wx],dfn[wx],dep[wx],size[wx],son[wx],top[wx],fa[wx];
void Swap(int &x,int &y){
int temp=x;x=y;y=temp;
}
void add(int from,int to,int dis){
edge[++num].nxt=head[from];
edge[num].to=to;
edge[num].dis=dis;
head[from]=num;
}
void up(int o){
ma(o)=max(ma(ls(o)),ma(rs(o)));
}
void down(int o){
if(ta(o)>=0){ta(ls(o))=ma(ls(o))=ta(rs(o))=ma(rs(o))=ta(o);tag(ls(o))=tag(rs(o))=0;}
if(tag(o)){
ma(ls(o))+=tag(o);
ma(rs(o))+=tag(o);
tag(ls(o))+=tag(o);
tag(rs(o))+=tag(o);
}
ta(o)=-1;
tag(o)=0;
}
void build(int o,int l,int r){
t[o].l=l;t[o].r=r;t[o].ta=-1;
if(l==r){ma(o)=a[tid[l]];return;}
int mid=t[o].l+t[o].r>>1;
build(ls(o),l,mid);
build(rs(o),mid+1,r);
up(o);
}
void update_add(int o,int l,int r,int k){
if(l<=t[o].l&&t[o].r<=r){
ma(o)+=k;
tag(o)+=k;
return;
}
down(o);
int mid=t[o].l+t[o].r>>1;
if(l<=mid)update_add(ls(o),l,r,k);
if(r>mid)update_add(rs(o),l,r,k);
up(o);
}
void update_change(int o,int l,int r,int k){
if(l<=t[o].l&&t[o].r<=r){
ma(o)=k;ta(o)=k;tag(o)=0;
return;
}
down(o);
int mid=t[o].l+t[o].r>>1;
if(l<=mid)update_change(ls(o),l,r,k);
if(r>mid)update_change(rs(o),l,r,k);
up(o);
}
int query(int o,int l,int r){
if(l<=t[o].l&&t[o].r<=r){
return t[o].ma;
}
down(o);
int maxn=-1;
int mid=t[o].l+t[o].r>>1;
if(l<=mid)maxn=max(maxn,query(ls(o),l,r));
if(r>mid)maxn=max(maxn,query(rs(o),l,r));
return maxn;
}
void dfs_a(int u,int father){
fa[u]=father;size[u]=1;dep[u]=dep[father]+1;
int maxson=-1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v==father)continue;
a[v]=edge[i].dis;
f[v][0]=u;
dfs_a(v,u);
size[u]+=size[v];
if(size[v]>maxson){
maxson=size[v];
son[u]=v;
}
}
}
void dfs_b(int u,int topf){
dfn[u]=++tot;
top[u]=topf;
tid[tot]=u;
if(son[u])dfs_b(son[u],topf);
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v==fa[u]||v==son[u])continue;
dfs_b(v,v);
}
}
int C_query(int x,int y){
int fx=top[x],fy=top[y];
int maxn=-1;
while(fx!=fy){
if(dep[fx]>=dep[fy])maxn=max(maxn,query(1,dfn[fx],dfn[x])),x=fa[fx];
else maxn=max(maxn,query(1,dfn[fy],dfn[y])),y=fa[fy];
fx=top[x];fy=top[y];
}
if(dfn[x]>dfn[y])swap(x,y);
maxn=max(maxn,query(1,dfn[x],dfn[y]));
return maxn;
}
void C_update_add(int x,int y,int k){
int fx=top[x],fy=top[y];
while(fx!=fy){
if(dep[fx]>=dep[fy])update_add(1,dfn[fx],dfn[x],k),x=fa[fx];
else update_add(1,dfn[fy],dfn[y],k),y=fa[fy];
fx=top[x];fy=top[y];
}
if(dfn[x]>dfn[y])swap(x,y);
update_add(1,dfn[x],dfn[y],k);
}
void C_update_change(int x,int y,int k){
int fx=top[x],fy=top[y];
while(fx!=fy){
if(dep[fx]>=dep[fy])update_change(1,dfn[fx],dfn[x],k),x=fa[fx];
else update_change(1,dfn[fy],dfn[y],k),y=fa[fy];
fx=top[x];fy=top[y];
}
if(dfn[x]>dfn[y])swap(x,y);
update_change(1,dfn[x],dfn[y],k);
}
void pre(){
for(int j=1;j<=21;j++)for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
}
int LCA(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=21;i>=0;i--){
if(dep[f[x][i]]>=dep[y])x=f[x][i];
}
if(x==y)return x;
for(int i=21;i>=0;i--){
if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
}
return f[x][0];
}
signed main(){
n=read();
for(int i=1;i<n;i++){
x=read();y=read();z=read();
add(x,y,z);add(y,x,z);
// printf("debug~~~~~~~~~~\n");
// printf("%d %d %d\n",x,y,z);
// printf("debug~~~~~~~~~~\n");
}
dfs_a(1,0);dfs_b(1,1);build(1,1,n);
pre();
while(1){
scanf("%s",opt+1);
if(opt[1]=='S')break;
else if(opt[2]=='h'){
x=read();y=read();
if(dep[edge[x*2].to]>dep[edge[x*2-1].to]){
update_change(1,dfn[edge[x*2].to],dfn[edge[x*2].to],y);
}
else update_change(1,dfn[edge[x*2-1].to],dfn[edge[x*2-1].to],y);
}
else if(opt[2]=='o'){
x=read();y=read();k=read();
int lca=LCA(x,y);
int tmp=query(1,dfn[lca],dfn[lca]);
C_update_change(x,y,k);
update_change(1,dfn[lca],dfn[lca],tmp);
}
else if(opt[1]=='A'){
x=read();y=read();z=read();
int lca=LCA(x,y);int tmp=query(1,dfn[lca],dfn[lca]);
C_update_add(x,y,z);
update_change(1,dfn[lca],dfn[lca],tmp);
}
else{
x=read();y=read();
int lca=LCA(x,y);int tmp=query(1,dfn[lca],dfn[lca]);
update_change(1,dfn[lca],dfn[lca],-521);
else printf("%lld\n",C_query(x,y));
update_change(1,dfn[lca],dfn[lca],tmp);
}
}
return 0;
}