樹鏈剖分 月下毛景樹
月下“毛景樹”
題目描述
毛毛蟲經過及時的變形,最終逃過的一劫,離開了菜媽的菜園。 毛毛蟲經過千山萬水,歷盡千辛萬苦,最後來到了小小的紹興一中的校園裏。
爬啊爬
毛毛蟲爬到了一顆小小的“毛景樹”下面,發現樹上長著他最愛吃的毛毛果~ “毛景樹”上有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;
}
樹鏈剖分 月下毛景樹