[luogu4315] 月下“毛景樹”
阿新 • • 發佈:2018-11-25
這題真棒!
首先是這題是邊權題,為了方便處理,化為點權。可一條邊有兩點點啊,用哪個存權值好呢?當然是兒子啦!因為一個兒子唯一對應一個連著父親的邊。
然後這題對於線段樹涉及到區間最值查詢、區間修改、區間加、單點修改,我很偷懶地把單點修改弄成區間修改了。
那麼運算優先順序問題:區間覆蓋優於區間加,因為一旦有一個區間覆蓋出現,之前所有的區間加都可以情空,處理起來很方便。
那麼就是剖分的問題了:你會發現路徑上的LCA存的值,是屬於LCA和它父親的邊,一定不在這條路徑上,所以不可以訪問。最初考慮求出LCA,然後單點修改,區間操作,然後再單點修改。但是這樣很麻煩啊……厚顏無恥地看了題解……你會發現我們在剖分的過程中,最後一定會跳到同一條重鏈上,深度小的就是LCA!!!那麼我們可以怎麼不去訪問它呢?只需要把它的dfs序+1即可,因為這是一條重鏈,+1後就是它的重兒子!還可以保證區間不會斷!
#include <cstdio> #include <cstring> #include <algorithm> #define MAXN 100005 #define lson (rt<<1) #define rson (rt<<1|1) #define mid ((l+r)>>1) struct table { int v,w,next; }G[MAXN<<1]; struct edge { int u,v,w; }E[MAXN]; int head[MAXN]; int dfn[MAXN],top[MAXN],val[MAXN]; int size[MAXN],son[MAXN],son_w[MAXN],d[MAXN],fa[MAXN]; int seg[MAXN<<2],tag[MAXN<<2],sum[MAXN<<2]; int N,tot = 0,num = 0; inline void add(int u,int v,int w) { G[++tot].v = v;G[tot].w = w;G[tot].next = head[u];head[u] = tot; } inline void pushup(int rt) { seg[rt] = std::max(seg[lson],seg[rson]); } void Build(int rt,int l,int r) { tag[rt] = -1; sum[rt] = 0; if(l==r) { seg[rt] = val[l]; return; } Build(lson,l,mid); Build(rson,mid+1,r); pushup(rt); } inline void pushdown(int rt) { if(tag[rt]!=-1) { sum[lson] = sum[rson] = 0; tag[lson] = tag[rson] = seg[lson] = seg[rson] = tag[rt]; tag[rt] = -1; } sum[lson] += sum[rt];sum[rson] += sum[rt]; seg[lson] += sum[rt];seg[rson] += sum[rt]; sum[rt] = 0; } void sum_update(int C,int L,int R,int rt,int l,int r) { if(L<=l&&R>=r) { seg[rt] += C; sum[rt] += C; return; } if(L>r||R<l) return; pushdown(rt); if(L<=mid) sum_update(C,L,R,lson,l,mid); if(r>mid) sum_update(C,L,R,rson,mid+1,r); pushup(rt); } void tag_update(int C,int L,int R,int rt,int l,int r) { if(L<=l&&R>=r) { seg[rt] = C; sum[rt] = 0; tag[rt] = C; return; } if(L>r||R<l) return; pushdown(rt); if(L<=mid) tag_update(C,L,R,lson,l,mid); if(r>mid) tag_update(C,L,R,rson,mid+1,r); pushup(rt); } int query(int L,int R,int rt,int l,int r) { if(L<=l&&R>=r) return seg[rt]; if(L>r||R<l) return 0; pushdown(rt); int maxx = 0; if(L<=mid) maxx = query(L,R,lson,l,mid); if(r>mid) maxx = std::max(maxx,query(L,R,rson,mid+1,r)); pushup(rt); return maxx; } void dfs1(int u,int father) { d[u] = d[father] + 1; size[u] = 1; son[u] = 0; son_w[u] = 0; fa[u] = father; for(int i=head[u];i;i=G[i].next) { int v = G[i].v; if(v==father) continue; dfs1(v,u); size[u] += size[v]; if(size[son[u]]<size[v]) son[u] = v,son_w[u] = G[i].w; } } void dfs2(int u,int tp,int w) { dfn[u] = ++num; val[num] = w; top[u] = tp; if(son[u]) dfs2(son[u],tp,son_w[u]); for(int i=head[u];i;i=G[i].next) { int v = G[i].v; if(v==fa[u]||v==son[u]) continue; dfs2(v,v,G[i].w); } } inline void chain_sum_update(int u,int v,int w) { while(top[u]!=top[v]) { if(d[top[u]]<d[top[v]]) std::swap(u,v); sum_update(w,dfn[top[u]],dfn[u],1,1,N); u = fa[top[u]]; } if(d[u]>d[v]) std::swap(u,v); sum_update(w,dfn[u]+1,dfn[v],1,1,N); } inline void chain_tag_update(int u,int v,int w) { while(top[u]!=top[v]) { if(d[top[u]]<d[top[v]]) std::swap(u,v); tag_update(w,dfn[top[u]],dfn[u],1,1,N); u = fa[top[u]]; } if(d[u]>d[v]) std::swap(u,v); tag_update(w,dfn[u]+1,dfn[v],1,1,N); } inline int chain_query(int u,int v) { int maxx = 0; while(top[u]!=top[v]) { if(d[top[u]]<d[top[v]]) std::swap(u,v); maxx = std::max(maxx,query(dfn[top[u]],dfn[u],1,1,N)); u = fa[top[u]]; } if(d[u]>d[v]) std::swap(u,v); maxx = std::max(maxx,query(dfn[u]+1,dfn[v],1,1,N)); return maxx; } inline int get_opt() { char ch = getchar();int opt = 0; while(ch<'A'||ch>'Z') ch = getchar(); if(ch=='M') opt = 1; else if(ch=='A') opt = 2; else if(ch=='C') { ch = getchar(); if(ch=='h') opt = 3; else opt = 4; } else if(ch=='S') opt = 0; while(ch!=' '&&ch!='\n'&&ch!=EOF) ch = getchar(); return opt; } int main() { int u,v,w; scanf("%d",&N); for(int i=1;i<N;++i) { scanf("%d%d%d",&u,&v,&w); E[i] = (edge){u,v}; add(u,v,w); add(v,u,w); } d[0] = size[0] = 0; dfs1(1,0); dfs2(1,0,0); Build(1,1,N); int opt; while((opt = get_opt())!=0) { if(opt==1) { scanf("%d%d",&u,&v); printf("%d\n",chain_query(u,v)); } else if(opt==2) { scanf("%d%d%d",&u,&v,&w); chain_sum_update(u,v,w); } else if(opt==3) { scanf("%d%d",&u,&w); chain_tag_update(E[u].u,E[u].v,w); } else if(opt==4) { scanf("%d%d%d",&u,&v,&w); chain_tag_update(u,v,w); } } return 0; }