[题解]P1505 [国家集训队]旅游
看到树上点对之间的修改和询问就知道是树剖了。
由于询问和操作都是在边上,我们还需要将边权转为点权。与其他树剖题不同的是,C i
操作需要我们直接修改一条指定的边的边权,而不是修改两点之间的边权,所以我们还需要记录每条边将边权转到了哪个点上。
具体操作方法:
il void dfs1(int x,int fa)
{
siz[x]=1;son[x]=0;dep[x]=dep[fa]+1;f[x]=fa;
for(re int i=h[x];i;i=e[i].nxt)
if(e[i].v^fa)
{
etp[(i+1)>>1]=e[i].v;
W[e[i].v]=e[i].w;
dfs1(e[i].v,x);
siz[x]+=siz[e[i].v];
son[x]=siz[son[x]]<siz[e[i].v]?e[i].v:son[x];
}
}
我们可以在第一次\(\text{dfs}\)中存下每条边指向的儿子的编号,也就代码中的ept[]
(\(edge\ to\ point\))。
解决了边转点的问题后,我们再来考虑如何用线段树来维护题目要求的操作。
-
C i
就是在\(dfn[etp[i]]\)上单点修改il void change1(int p,int pos,int x) { if(L[p]==R[p]){Sum[p]=Max[p]=Min[p]=x;return;} re int mid=(L[p]+R[p])>>1; pushdown(p); if(pos>mid) change1(rs(p),pos,x); else change1(ls(p),pos,x); pushup(p); } il void modify1(int p,int w){change1(1,dfn[p],w);} if(ch=='C') modify1(etp[u],v);
-
N u v
区间取反,也就是区间乘以\(-1\)(注意最大值和最小值要交换)il void pushdown(int p) { if(!lz[p]) return; Sum[ls(p)]*=-1;Sum[rs(p)]*=-1; swap(Max[ls(p)],Min[ls(p)]); swap(Max[rs(p)],Min[rs(p)]); Max[ls(p)]*=-1;Min[ls(p)]*=-1; Max[rs(p)]*=-1;Min[rs(p)]*=-1; lz[ls(p)]^=1;lz[rs(p)]^=1; lz[p]=0; } il void change2(int p,int l,int r) { if(L[p]>r||R[p]<l) return; if(L[p]>=l&&R[p]<=r) { lz[p]^=1; Sum[p]*=-1; swap(Max[p],Min[p]); Max[p]*=-1;Min[p]*=-1; return; } pushdown(p); change2(ls(p),l,r); change2(rs(p),l,r); pushup(p); } il void modify2(int u,int v) { while(top[u]^top[v]) { if(dep[top[u]]<dep[top[v]]) swap(u,v); change2(1,dfn[top[u]],dfn[u]); u=f[top[u]]; } if(dep[u]<dep[v]) swap(u,v); change2(1,dfn[v]+1,dfn[u]); } if(ch=='N') modify2(u+1,v+1);
-
SUM u v
也就是区间求和il int query1(int p,int l,int r) { if(L[p]>r||R[p]<l) return 0; if(L[p]>=l&&R[p]<=r) return Sum[p]; pushdown(p); return query1(ls(p),l,r)+query1(rs(p),l,r); } il int ask1(int u,int v) { re int res=0; while(top[u]^top[v]) { if(dep[top[u]]<dep[top[v]]) swap(u,v); res+=query1(1,dfn[top[u]],dfn[u]); u=f[top[u]]; } if(dep[u]<dep[v]) swap(u,v); res+=query1(1,dfn[v]+1,dfn[u]); return res; } if(ch=='S') print(ask1(u+1,v+1));
-
MAX u v
和MIN u v
区间最值查询il int query2(int p,int l,int r) { if(L[p]>r||R[p]<l) return -inf; if(L[p]>=l&&R[p]<=r) return Max[p]; pushdown(p); return max(query2(ls(p),l,r),query2(rs(p),l,r)); } il int query3(int p,int l,int r) { if(L[p]>r||R[p]<l) return inf; if(L[p]>=l&&R[p]<=r) return Min[p]; pushdown(p); return min(query3(ls(p),l,r),query3(rs(p),l,r)); } il int ask2(int u,int v) { re int res=-inf; while(top[u]^top[v]) { if(dep[top[u]]<dep[top[v]]) swap(u,v); res=max(res,query2(1,dfn[top[u]],dfn[u])); u=f[top[u]]; } if(dep[u]<dep[v]) swap(u,v); res=max(res,query2(1,dfn[v]+1,dfn[u])); return res; } il int ask3(int u,int v) { re int res=inf; while(top[u]^top[v]) { if(dep[top[u]]<dep[top[v]]) swap(u,v); res=min(res,query3(1,dfn[top[u]],dfn[u])); u=f[top[u]]; } if(dep[u]<dep[v]) swap(u,v); res=min(res,query3(1,dfn[v]+1,dfn[u])); return res; } if(ch=='A') print(ask2(u+1,v+1)); if(ch=='I') print(ask3(u+1,v+1));
完整代码太长,就不给了。