基操
T1 板/[Vani有约会]雨天的尾巴 /【模板】线段树合并
多次给树上路径上的点加一个数,求每个节点上加得最多的数
差分,然后加回来
普通差分:维护一个值即可
现在:合并一个数组,使用线段树合并
自己查出来70行少打了一个+=
✌️
就很板
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<3)+(i<<1)+ch-48,ch=getchar();
return i*f;
}
#define pb push_back
const int N=5e5+5,k=1e5;
int n,m,res[N],sz;
int dep[N],f[N][25];
vector<int>G[N];
int root[N];
struct node{
int lch,rch,val,ans;
}tre[N*20];
void DFS(int u,int fa){
dep[u]=dep[fa]+1;
f[u][0]=fa;
for(int v:G[u]) if(v^fa) DFS(v,u);
}
int lca(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
for(int l=20;l>=0;--l)
if(dep[f[u][l]]>=dep[v])
u=f[u][l];
if(u==v) return u;
for(int l=20;l>=0;--l)
if(f[u][l]!=f[v][l])
u=f[u][l],v=f[v][l];
return f[u][0];
}
void push_up(int p){
if(tre[tre[p].lch].val<=0&&tre[tre[p].rch].val<=0) return;
if(tre[tre[p].lch].val>=tre[tre[p].rch].val){
tre[p].val=tre[tre[p].lch].val;
tre[p].ans=tre[tre[p].lch].ans;
}else{
tre[p].val=tre[tre[p].rch].val;
tre[p].ans=tre[tre[p].rch].ans;
}
return;
}
void update(int &p,int l,int r,int w,int v){
if(!p) p=++sz;
if(l==r){
tre[p].val+=v;
tre[p].ans=tre[p].val>0?l:0;
return;
}
int mid=l+r>>1;
if(w<=mid) update(tre[p].lch,l,mid,w,v);
else update(tre[p].rch,mid+1,r,w,v);
push_up(p);
return;
}
int merge(int p,int rt,int l,int r){
if(!p||!rt) return p|rt;
if(l==r){
tre[p].val+=tre[rt].val;
tre[p].ans=tre[p].val>0?l:0;
return p;
}
int mid=l+r>>1;
tre[p].lch=merge(tre[p].lch,tre[rt].lch,l,mid);
tre[p].rch=merge(tre[p].rch,tre[rt].rch,mid+1,r);
push_up(p);
return p;
}
void work(int u,int fa){
for(int v:G[u]) if(v^fa){
work(v,u);
root[u]=merge(root[u],root[v],1,k);
}
res[u]=tre[root[u]].ans;
return;
}
int main(){
n=in,m=in;
for(int i=1;i<n;++i){
int u=in,v=in;
G[u].pb(v);
G[v].pb(u);
}
DFS(1,0);
for(int l=1;l<=20;++l)
for(int u=1;u<=n;++u)
f[u][l]=f[f[u][l-1]][l-1];
for(int i=1;i<=m;++i){
int u=in,v=in,w=in,s=lca(u,v);
update(root[u],1,k,w,1);
update(root[v],1,k,w,1);
update(root[s],1,k,w,-1);
update(root[f[s][0]],1,k,w,-1);
}
work(1,0);
for(int i=1;i<=n;++i)
printf("%d\n",res[i]);
return 0;
}
T2 天天爱跑步
背景:这是我咕的一道题
当时学差分,还不会线段树合并,就做不了(似乎差分可以写,但是很难想)
将链拆成两段
u
→
l
c
a
,
l
c
a
→
v
u\to lca,lca\to v
u→lca,lca→v
发现有:
d
e
p
u
=
d
e
p
i
+
w
i
d
e
p
u
−
d
e
p
l
c
a
+
d
e
p
i
−
d
e
p
l
c
a
=
w
i
⇒
d
e
p
u
−
2
d
e
p
l
c
a
=
w
i
−
d
e
p
i
dep_u=dep_i+w_i\\ dep_u-dep_{lca}+dep_i-dep_{lca}=w_i\Rightarrow dep_u-2dep_{lca}=w_i-dep_i
depu=depi+widepu−deplca+depi−deplca=wi⇒depu−2deplca=wi−depi
分开看就行了
可能产生负数,故线段树值域
[
−
N
,
N
]
[-N,N]
[−N,N]
lca算到前一段还是后一段都无所谓,统一为前一段
42行的+=
没查出来😭
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<3)+(i<<1)+ch-48,ch=getchar();
return i*f;
}
#define pb push_back
const int N=3e5+5,R=3e5,NN=N*20;
int n,m,dep[N],sz,f[N][25],tim[N],root[N];
vector<int>G[N];
int res[N],lch[NN],rch[NN],val[NN][2];
void DFS(int u,int fa){dep[u]=dep[fa]+1; f[u][0]=fa; for(int v:G[u]) if(v^fa) DFS(v,u);}
int lca(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
for(int l=20;l>=0;--l)
if(dep[f[u][l]]>=dep[v])
u=f[u][l];
if(u==v) return u;
for(int l=20;l>=0;--l)
if(f[u][l]!=f[v][l])
u=f[u][l],v=f[v][l];
return f[u][0];
}
void push_up(int p){
if(!lch[p]&&!rch[p]) return;
val[p][0]=val[lch[p]][0]+val[rch[p]][0];
val[p][1]=val[lch[p]][1]+val[rch[p]][1];
return;
}
void update(int &p,int l,int r,int w,int v,int c){
if(!p) p=++sz;
if(l==r){
val[p][c]+=v;
return;
}
int mid=l+r>>1;
if(w<=mid) update(lch[p],l,mid,w,v,c);
else update(rch[p],mid+1,r,w,v,c);
push_up(p);
return;
}
int merge(int p,int rt,int l,int r){
if(!p||!rt) return p|rt;
if(l==r){
val[p][0]+=val[rt][0];
val[p][1]+=val[rt][1];
return p;
}
int mid=l+r>>1;
lch[p]=merge(lch[p],lch[rt],l,mid);
rch[p]=merge(rch[p],rch[rt],mid+1,r);
push_up(p);
return p;
}
int query(int p,int l,int r,int w,int c){
if(!p) return 0;
if(l==r) return val[p][c];
int mid=l+r>>1;
if(w<=mid) return query(lch[p],l,mid,w,c);
else return query(rch[p],mid+1,r,w,c);
}
void work(int u,int fa){
for(int v:G[u]) if(v^fa){
work(v,u);
root[u]=merge(root[u],root[v],-R,R);
}
res[u]+=query(root[u],-R,R,dep[u]+tim[u],0);
res[u]+=query(root[u],-R,R,tim[u]-dep[u],1);
return;
}
int main(){
n=in,m=in;
for(int i=1;i<n;++i){
int u=in,v=in;
G[u].pb(v);
G[v].pb(u);
}
DFS(1,0);
for(int l=1;l<=20;++l)
for(int u=1;u<=n;++u)
f[u][l]=f[f[u][l-1]][l-1];
for(int i=1;i<=n;++i) tim[i]=in;
for(int i=1;i<=m;++i){
int s=in,t=in,l=lca(s,t);
update(root[s],-R,R,dep[s],1,0);
update(root[f[l][0]],-R,R,dep[s],-1,0);
update(root[t],-R,R,dep[s]-2*dep[l],1,1);
update(root[l],-R,R,dep[s]-2*dep[l],-1,1);
}
work(1,0);
for(int i=1;i<=n;++i)
printf("%d ",res[i]);
return 0;
}