版权声明:小蒟蒻的博客转载也请注明出处哦 https://blog.csdn.net/qq_42835823/article/details/86625169
月下“毛景树”
应该一看都知道是树链剖分吧,但这道题细节特别多。
- 把边权转到深度较深的点上,这样可以用树链剖分操作了
- 操作路径的时候,两个点的 不能被改动和统计
- 懒标记需要两个,且覆盖标记的优先级要高于加的标记,每次传递,修改覆盖标记,要把加标记清为零
- 覆盖标记初始化为 ,因为可能会覆盖为零
- 最好不要复制粘贴,有些地方未修改到,就很难查错
- 单个树枝的修改要找到那条树枝中深度较深的点再修改
最重要的: 板子别打错!!!
向上跳
找
时应是
而非
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct edge{
int v,w,nxt;
}e[N<<1];
int first[N],cnt=0;
inline void add(int u,int v,int w){
e[++cnt].v=v;e[cnt].w=w;
e[cnt].nxt=first[u];first[u]=cnt;
}
int fa[N],dep[N],siz[N],son[N],pos[N],idx[N],top[N],tot,val[N];
void dfs1(int x,int f){
fa[x]=f;
dep[x]=dep[f]+1;
siz[x]=1;
for(int i=first[x];i;i=e[i].nxt){
int v=e[i].v;
if(v==f)continue;
dfs1(v,x);
siz[x]+=siz[v];
if(siz[v]>siz[son[x]])son[x]=v;
val[v]=e[i].w;
}
}
void dfs2(int x){
if(son[x]){
pos[son[x]]=++tot;
idx[tot]=son[x];
top[son[x]]=top[x];
dfs2(son[x]);
}
for(int i=first[x];i;i=e[i].nxt){
int v=e[i].v;
if(v==son[x]||v==fa[x])continue;
pos[v]=++tot;
idx[tot]=v;
top[v]=v;
dfs2(v);
}
}
#define lc (p<<1)
#define rc (p<<1|1)
struct tree{
int l,r,mx,laz1,laz2;//改和加
}t[N<<2];
int n;
void build(int p,int l,int r){
t[p].l=l;t[p].r=r;t[p].laz1=-1;t[p].laz2=0;
if(l==r){
t[p].mx=val[idx[l]];
return;
}
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
t[p].mx=max(t[lc].mx,t[rc].mx);
}
void init(){
dfs1(1,0);
idx[1]=top[1]=pos[1]=tot=1;
dfs2(1);
build(1,1,n);
}
void pushdown(int p){//////////////////////////////////
if(~t[p].laz1){
t[lc].mx=t[p].laz1;
t[lc].laz1=t[p].laz1;
t[lc].laz2=0;
t[rc].mx=t[p].laz1;
t[rc].laz1=t[p].laz1;
t[rc].laz2=0;
t[p].laz1=-1;
}
if(t[p].laz2>0){
t[lc].mx+=t[p].laz2;
t[lc].laz2+=t[p].laz2;
t[rc].mx+=t[p].laz2;
t[rc].laz2+=t[p].laz2;
t[p].laz2=0;
}
}
void ADD(int p,int l,int r,int v){
if(l<=t[p].l&&t[p].r<=r){
t[p].mx+=v;
t[p].laz2+=v;
return;
}
pushdown(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid)ADD(lc,l,r,v);
if(mid<r)ADD(rc,l,r,v);
t[p].mx=max(t[lc].mx,t[rc].mx);
}
void change(int p,int l,int r,int v){
if(l<=t[p].l&&t[p].r<=r){
t[p].mx=v;
t[p].laz1=v;//
t[p].laz2=0;//如果直接覆盖,就不用再加了
return;
}
pushdown(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid)change(lc,l,r,v);
if(mid<r)change(rc,l,r,v);
t[p].mx=max(t[lc].mx,t[rc].mx);
}
int query(int p,int l,int r){
if(l<=t[p].l&&t[p].r<=r)return t[p].mx;
pushdown(p);
int mid=(t[p].l+t[p].r)>>1,ans=-2e9;
if(l<=mid)ans=max(ans,query(lc,l,r));
if(mid<r)ans=max(ans,query(rc,l,r));
return ans;
}
void pathadd(int u,int v,int w){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
ADD(1,pos[top[u]],pos[u],w);
u=fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
ADD(1,pos[v]+1,pos[u],w);//不算LCA
}
void pathchange(int u,int v,int w){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
change(1,pos[top[u]],pos[u],w);
u=fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
change(1,pos[v]+1,pos[u],w);//不算LCA
}
int pathquery(int u,int v){
int ans=-2e9;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);//---加上top---------------------------------------------------------------------------//
ans=max(ans,query(1,pos[top[u]],pos[u]));
u=fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
ans=max(ans,query(1,pos[v]+1,pos[u]));//不算LCA
return ans;
}
int u[N],v[N],w[N];
int main(){
scanf("%d",&n);
for(int i=1;i<n;i++){
scanf("%d%d%d",&u[i],&v[i],&w[i]);
add(u[i],v[i],w[i]);add(v[i],u[i],w[i]);
}
init();
char s[10];
int x,y,z;
while(1){
scanf("%s",s+1);
if(s[1]=='S')break;
if(s[1]=='C'&&s[2]=='h'){
scanf("%d%d",&x,&y);
if(dep[u[x]]>dep[v[x]])change(1,pos[u[x]],pos[u[x]],y);
else change(1,pos[v[x]],pos[v[x]],y);//修改树枝
}
if(s[1]=='C'&&s[2]=='o'){
scanf("%d%d%d",&x,&y,&z);
pathchange(x,y,z);
}
if(s[1]=='A'){
scanf("%d%d%d",&x,&y,&z);
pathadd(x,y,z);
}
if(s[1]=='M'){
scanf("%d%d",&x,&y);
printf("%d\n",pathquery(x,y));
}
}
return 0;
}