点分治学习笔记
点分治就是在树上拿点分治
但是只能按照某个点对一个子树进行处理,所以一般处理路径问题
主要是找到重心,然后一直向下递归
找中心有个比较吊的写法,直接拿上一次这个点得到的大小作为子树大小求重心,正确性不会证明,直接用吧。
贴个代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,ma[10005],siz[10005],sum,q[10005],t[10000005],ans[10005],rt;
vector<pair<int,int>> e[10005];
bool vis[10005];
void getroot(int p,int fa){
siz[p]=1;ma[p]=0;
for(auto tmp:e[p]){
int i=tmp.first;
if(i==fa||vis[i])continue;
getroot(i,p);
siz[p]+=siz[i];
ma[p]=max(ma[p],siz[i]);
}
ma[p]=max(ma[p],sum-siz[p]);
if(ma[p]<ma[rt])rt=p;
}
void dfs(int p,int fa,int dis,int op){
if(dis>1e7)return;
if(!op){
for(int i=1;i<=m;i++)if(dis<=q[i])ans[i]+=t[q[i]-dis];
}
else t[dis]+=op;
for(auto tmp:e[p]){
int i=tmp.first,w=tmp.second;
if(i==fa||vis[i])continue;
dfs(i,p,dis+w,op);
}
}
void dfs0(int p){
vis[p]=t[0]=1;
for(auto tmp:e[p]){
int i=tmp.first,w=tmp.second;
if(vis[i])continue;
dfs(i,0,w,0);
dfs(i,0,w,1);
}
for(auto tmp:e[p]){
int i=tmp.first,w=tmp.second;
if(vis[i])continue;
dfs(i,0,w,-1);
}
for(auto tmp:e[p]){
int i=tmp.first,w=tmp.second;
if(vis[i])continue;
sum=siz[i];
rt=0;
getroot(i,p);
dfs0(rt);
}
}
signed main(){
cin>>n>>m;
for(int i=1,u,v,w;i<n;i++){
cin>>u>>v>>w;
e[u].push_back({v,w});
e[v].push_back({u,w});
}
for(int i=1;i<=m;i++)cin>>q[i];
ma[0]=sum=n;
getroot(1,0);
dfs0(rt);
for(int i=1;i<=m;i++){
if(ans[i])puts("AYE");
else puts("NAY");
}
return 0;
}
然后是点分树
就是按照点分治的顺序遍历,然后直接就能按照树高进行修改操作了
然后可以在每个点存下所有子孙,比较方便
经典的记录这个子树给父亲的贡献搞一手容斥,点分树基本套路,一般都需要容↗斥↘技↘巧~
然后一般就解决了
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,a[100005],dep[100005],st[100005][18],rt,sum,ma[100005],siz[100005],pre[100005],siz2[100005];
bool vis[100005];
vector<int> e[100005];
vector<int> c[2][100005];
void pre_dfs(int p,int fa){
dep[p]=dep[fa]+1;
st[p][0]=fa;
for(int i=1;i<18;i++)st[p][i]=st[st[p][i-1]][i-1];
for(int i:e[p]){
if(i==fa)continue;
pre_dfs(i,p);
}
}
int LCA(int l,int r){
if(dep[l]<dep[r])swap(l,r);
for(int i=17;i>=0;i--)if(dep[st[l][i]]>=dep[r])l=st[l][i];
if(l==r)return l;
for(int i=17;i>=0;i--){
if(st[l][i]!=st[r][i]){
l=st[l][i];
r=st[r][i];
}
}
return st[l][0];
}
int get_dis(int u,int v){
return dep[u]+dep[v]-2*dep[LCA(u,v)];
}
void maxx(int &x,int y){
x=x>y?x:y;
}
void getroot(int p,int fa){
siz[p]=1,ma[p]=0;
for(int i:e[p]){
if(i!=fa&&!vis[i]){
getroot(i,p);
siz[p]+=siz[i];
ma[p]=max(ma[p],siz[i]);
}
}
ma[p]=max(ma[p],sum-siz[p]);
if(ma[p]<ma[rt])rt=p;
}
void build_dfs(int p){
vis[p]=1;
siz2[p]=sum+1;
c[0][p].resize(siz2[p]+1);
c[1][p].resize(siz2[p]+1);
for(int i:e[p]){
if(!vis[i]){
rt=0,sum=siz[i];
getroot(i,0);
pre[rt]=p;
build_dfs(rt);
}
}
}
int lowbit(int x){
return x&-x;
}
void add(int u,int op,int x,int v){
x++;
for(int i=x;i<=siz2[u];i+=lowbit(i))c[op][u][i]+=v;
}
int query(int u,int op,int x){
x++;
int res=0;
x=min(x,siz2[u]);
for(int i=x;i;i-=lowbit(i))res+=c[op][u][i];
return res;
}
void change(int p,int v){
for(int i=p;i;i=pre[i])add(i,0,get_dis(p,i),v);
for(int i=p;pre[i];i=pre[i])add(i,1,get_dis(p,pre[i]),v);
}
int ask(int x,int y){
int ans=query(x,0,y);
for(int i=x;pre[i];i=pre[i]){
int dis=get_dis(x,pre[i]);
if(y>=dis)ans+=query(pre[i],0,y-dis)-query(i,1,y-dis);
}
return ans;
}
int read(){
char c=getchar();
int x=0;
while(c>'9'||c<'0')c=getchar();
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x;
}
signed main(){
n=read(),m=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1,u,v;i<n;i++){
u=read(),v=read();
e[u].push_back(v);
e[v].push_back(u);
}
pre_dfs(1,0);
ma[0]=sum=n,rt=0;
getroot(1,0);
build_dfs(rt);
for(int i=1;i<=n;i++)change(i,a[i]);
int la=0;
for(int i=1,op,x,y;i<=m;i++){
op=read(),x=read(),y=read();
x^=la,y^=la;
if(!op)la=ask(x,y),printf("%d\n",la);
else change(x,y-a[x]),a[x]=y;
}
return 0;
}

浙公网安备 33010602011771号