【学习记录】点分治
点分治之前就学过,最近机房有人让我帮调,曹神又给了道好题,自己又学了点分树,因此简单记录一下。
点分治即每次找到树的重心,并以其为中心分治,处理跨过中心的所有路径,再递归下去处理不经过中心的子树内路径。处理方式为枚举其子树,先处理该子树与之前子树之间的路径,再将该子树内的点记录下来以便之后查询。由于以重心为根时,其子树大小不超过
P3806 【模板】点分治 1
题意
给定一棵树,边有边权,
题解
板题,直接点分治,开桶记录目前是否存在与分治中心距离为
25.02-MX-D1T2 毒药
题意
给定一棵树,点有点权
题解
记
发现只有令含
本题点分治部分仅有基本应用,在计算贡献时用到了 Trie 树,这里清空只需要清掉开的所有点即可。可能没有提交通道,只有计算贡献部分的原题 P7502,之后有时间可能会造造数据。
P10421 [蓝桥杯 2023 国 A] 树上的路径
题意
给定一棵树,求树上所有长度在
题解
先点分治,考虑如何统计路径长度和。若枚举到
但还是不够优秀,考虑求贡献时的实质,其实是钦定顺序为
问题在于对桶做前缀和需要值域大小的复杂度,然而某子树内的
struct nod
{
ll s[N]; int len;
void cle(int x)
{
len=x;
for(int i=0;i<=len;i++) s[i]=0;
}
void add(int p,ll x) {s[p]+=x;}
void build() {for(int i=1;i<=len;i++) s[i]+=s[i-1];}
ll qry(int p) {return s[min(p,len)];}
}Ta[2],Tb[2];
void sol(int u)
{
d[u]=0,Ta[0].cle(siz[u]),Tb[0].cle(siz[u]),Ta[0].add(0,2);
for(int v:e[u]) if(!vis[v])
{
tt=0,dfs(v,u);
for(int i=1;i<=tt;i++) Ta[0].add(td[i],1),Tb[0].add(td[i],td[i]);
}
Ta[0].build(),Tb[0].build();
for(int v:e[u]) if(!vis[v])
{
tt=0,dfs(v,u),Ta[1].cle(siz[v]),Tb[1].cle(siz[v]);
for(int i=1;i<=tt;i++) Ta[1].add(td[i],1),Tb[1].add(td[i],td[i]);
Ta[1].build(),Tb[1].build();
for(int i=1;i<=tt;i++)
{
int l=max(0,L-td[i]),r=R-td[i];
if(l>r) continue;
ll x=Ta[0].qry(r)-Ta[1].qry(r),y=Tb[0].qry(r)-Tb[1].qry(r);
if(l) x-=(Ta[0].qry(l-1)-Ta[1].qry(l-1)),y-=(Tb[0].qry(l-1)-Tb[1].qry(l-1));
res+=x*td[i]+y;
}
}
}
CF2101E Kia Bakes a Cake
题意
给定一棵
题解
首先看到
之后考虑使用 DP 解决该问题,注意到 DP 状态中只能记录开头或结尾元素,难以限制两两不同。然而仔细考虑
因此 DP 就是可行的了,最朴素的 DP 状态为
这时想起答案不会超过
之后考虑转移,
考虑能否优化到
注意到查询的
P6329 【模板】点分树 | 震波
题意
给定一棵树,点有点权,需要支持单点修改,查询距某点不超过
题解
点分树是点分治的应用之一。具体地,令分治中心以上一层分治中心为父亲,建出一棵点分树。与点分治类似,点分树的深度不会超过
这时对于某两点
对于本题,有
时间复杂度为
signed main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m,mx[0]=n,T[0].build(n),T[1].build(n);
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<n;i++)
{
int u,v; cin>>u>>v;
e[u].pb(v),e[v].pb(u);
}
tot=n,getrt(1,0),ra=rt,getrt(rt,0),solv(rt),dfs0(1,0),dfs1(1,1),dfs2(ra);
for(int u=1;u<=n;u++) for(int i=id[u];i<id[u]+s[u];i++)
{
int v=p[i]; T[0].update(u,0,n,dis(v,u),a[v]);
if(f[u]) T[1].update(u,0,n,dis(v,f[u]),a[v]);
}
while(m--)
{
int op,x,y; cin>>op>>x>>y,x^=last,y^=last;
if(op)
{
int u=x,dt=y-a[x]; a[x]=y;
while(u)
{
if(f[u]) T[1].update(u,0,n,dis(x,f[u]),dt);
T[0].update(u,0,n,dis(x,u),dt),u=f[u];
}
}
else
{
int u=x,lp=x; last=0;
while(u)
{
int d=y-dis(u,x);
if(d>=0)
{
last+=T[0].query(u,0,n,0,d);
if(u!=x) last-=T[1].query(lp,0,n,0,d);
}
lp=u,u=f[u];
}
cout<<last<<'\n';
}
}
return 0;
}