题解:P14588 [LNCPC 2025] 前线支援
题解区怎么没我们简单易懂的根号做法。
根号做法除了常数大一点没有任何缺点。
下文默认求 LCA 复杂度
观察一些性质,我们发现对于一个修改,如果
但我们发现如果
于是我们考虑根号重构。具体地,对于非复杂修改直接维护。同时每
首先考虑如何
如果
如果
接下来考虑如何做到
我们设阈值为
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define int long long
#define gc getchar
//char buf[1<<20],*p1,*p2;
//#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define R read()
using namespace std;
int read()
{
int x=0,f=1;
char c=gc();
while(c>'9'||c<'0'){if(c=='-') f=-1;c=gc();}
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48,c=gc();
return x*f;
}
void write(int x,char xx)
{
static int st[35],top=0;
if(x<0){x=-x;putchar('-');}
do
{
st[top++]=x%10,x/=10;
}while(x);
while(top) putchar(st[--top]+48);
putchar(xx);
}
#define N 500010
int n,Q,fa[N],s[N],dfn[N],tot,id[N],siz[N],w[N],dep[N],st[21][N];
vector<int>g[N];
inline int op(int x,int y){return dep[x]<dep[y]?x:y;}
void dfs(int x)
{
siz[x]=1,s[x]=s[fa[x]]+w[x],dep[x]=dep[fa[x]]+1,dfn[x]=++tot,id[tot]=x;
for(auto i:g[x]) dfs(i),siz[x]+=siz[i];
}
#define ls (u<<1)
#define rs (u<<1|1)
#define mid (tr[u].l+tr[u].r>>1)
struct node{int l,r,su,lz1,cnt,suu,lz2;}tr[N<<2];
inline void upd(int u){tr[u].su=tr[ls].su+tr[rs].su,tr[u].suu=tr[ls].suu+tr[rs].suu;}
inline void c(int u,int x){tr[u].su+=(tr[u].r-tr[u].l+1)*x,tr[u].lz1+=x;}
inline void cc(int u,int x){tr[u].suu+=tr[u].cnt*x,tr[u].lz2+=x;}
inline void pd(int u)
{
if(tr[u].lz1){c(ls,tr[u].lz1),c(rs,tr[u].lz1),tr[u].lz1=0;}
if(tr[u].lz2){cc(ls,tr[u].lz2),cc(rs,tr[u].lz2),tr[u].lz2=0;}
}
void build(int u,int l,int r)
{
tr[u]={l,r};
if(l==r) return tr[u].cnt=s[id[l]],void(0);
build(ls,l,mid),build(rs,mid+1,r),tr[u].cnt=tr[ls].cnt+tr[rs].cnt;
}
void add(int u,int l,int r,int x)
{
if(l<=tr[u].l&&tr[u].r<=r) return c(u,x);
pd(u),(l<=mid&&(add(ls,l,r,x),1)),(r>mid&&(add(rs,l,r,x),1)),upd(u);
}
void Add(int u,int l,int r,int x)
{
if(l<=tr[u].l&&tr[u].r<=r) return cc(u,x);
pd(u),(l<=mid&&(Add(ls,l,r,x),1)),(r>mid&&(Add(rs,l,r,x),1)),upd(u);
}
pii que(int u,int l,int r)
{
if(l<=tr[u].l&&tr[u].r<=r) return {tr[u].su,tr[u].suu};
pd(u);
pii res={0,0};
if(l<=mid){pii t=que(ls,l,r);res.fi+=t.fi,res.se+=t.se;}
if(r>mid){pii t=que(rs,l,r);res.fi+=t.fi,res.se+=t.se;}
return res;
}
#undef ls
#undef rs
#undef mid
inline bool in(int x,int y){return !(dfn[y]<dfn[x]||dfn[y]>=dfn[x]+siz[x]);}
int lca(int u,int v)
{
if(dfn[u]>dfn[v]) swap(u,v);
if(in(u,v)) return u;
u=dfn[u],v=dfn[v];
int s=__lg(v-u+1);
return fa[op(st[s][u],st[s][v-(1<<s)+1])];
}
int dis(int x,int y){return s[x]+s[y]-2*s[lca(x,y)];}
int B,ans[N],W[N],S[N],SS[N];
vector<pii>v;
void reb()
{
for(int i=n;i>=1;i--) ans[i]-=ans[i-1],W[i]=0;
for(auto&[x,y]:v) W[y]++,W[fa[x]]--,add(1,dfn[x],dfn[x]+siz[x]-1,s[y]-2*s[fa[x]]),Add(1,dfn[x],dfn[x]+siz[x]-1,1);
for(int i=n;i>=1;i--) W[fa[id[i]]]+=W[id[i]];
for(int i=1;i<=n;i++) W[i]=W[i]*2*w[i];
W[0]=0;
for(int i=1;i<=n;i++) W[id[i]]+=W[fa[id[i]]];
v.clear();
for(int i=1;i<=n;i++) ans[i]+=ans[i-1]+W[id[i]];
}
int Qu(int x)
{
int sum=-(ans[dfn[x]+siz[x]-1]-ans[dfn[x]-1]);
for(auto[u,y]:v) if(in(u,x)||in(x,u))
{
u=(in(u,x)?x:u);
if(in(u,y)) sum+=siz[u]*(s[y]-2*s[fa[u]])+S[dfn[u]+siz[u]-1]-S[dfn[u]-1]-SS[y]+SS[fa[u]];
else sum+=siz[u]*(s[y]-2*s[lca(u,y)])+S[dfn[u]+siz[u]-1]-S[dfn[u]-1];
}
pii t=que(1,dfn[x],dfn[x]+siz[x]-1);
return t.fi+t.se+sum;
}
void solve()
{
n=R,Q=R,B=sqrt(n)+1;
for(int i=2;i<=n;i++) fa[i]=R,w[i]=R,g[fa[i]].pb(i);
dfs(1),build(1,1,n);
for(int i=1;i<=n;i++) st[0][i]=id[i],S[i]=S[i-1]+s[id[i]],SS[i]=2*siz[i]*w[i];
for(int i=1;i<=n;i++) SS[id[i]]+=SS[fa[id[i]]];
int LG=__lg(n);
for(int j=1;j<=LG;j++) for(int i=1;i+(1<<j)-1<=n;i++) st[j][i]=op(st[j-1][i],st[j-1][i+(1<<j-1)]);
while(Q--)
{
int op=R,x=R,y;
if(op==1)
{
y=R;
if(!in(x,y)) add(1,dfn[x],dfn[x]+siz[x]-1,s[y]-2*s[lca(x,y)]),Add(1,dfn[x],dfn[x]+siz[x]-1,1);
else v.pb({x,y});
}
else write(Qu(x),'\n');
if((int)v.size()>B) reb();
}
}
int T=1;
signed main()
{
// freopen("rescue.in","r",stdin);
// freopen("rescue.out","w",stdout);
// T=R;
while(T--) solve();
return 0;
}