[luogu4315] 月下“毛景树”
这题真棒!
首先是这题是边权题,为了方便处理,化为点权。可一条边有两点点啊,用哪个存权值好呢?当然是儿子啦!因为一个儿子唯一对应一个连着父亲的边。
然后这题对于线段树涉及到区间最值查询、区间修改、区间加、单点修改,我很偷懒地把单点修改弄成区间修改了。
那么运算优先级问题:区间覆盖优于区间加,因为一旦有一个区间覆盖出现,之前所有的区间加都可以情空,处理起来很方便。
那么就是剖分的问题了:你会发现路径上的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;
}