2022.03.11 点分树
2022.03.11 点分树
2.1 前置知识
2.1.1 点分治
点分治是每次选择子树中的重心不断更新答案的东西。
对于父节点x和子节点y,\(dis(x,y)=k\),可以先以x为子树中的根节点计算出除它自己外子树中任意两个节点u、v的dis。不过如果u、v的lca是y,那么相当于多计算了两遍从x到y,对此减去……抱歉,我还不会。
可以参考
https://blog.csdn.net/qq_39553725/article/details/77542223
2.2 点分树
2.2.1 点分树
把每次分治的重心连起来,就是一颗树。这棵树叫点分树。
因为是重心,所以树高不超过\(logn\)。一个新树上的子树表示它原本树上的连通块。所以原树上任意两点x、y在新树上的lca在原树上x到y的路径上,即\(dis(x,y)=dis(x,lca)+dis(lca,y)\)。
2.2.2 P6329 【模板】点分树 | 震波(点分树模板)
https://www.luogu.com.cn/problem/P6329
//https://www.luogu.com.cn/blog/SHEEP-BOLG/post-ti-xie-p6329-mu-ban-dian-fen-shu-zhen-bo
#include
using namespace std;
const int N=2e5+10;
int n,m,cnt,head[N],val[N],root,sizei[N],maxn[N],vis[N];
int tot,ind,fa[N],dep[N],true_id[N],f[N<<1][21],logi[N<<1];
struct node{
int to,next;
}a[N<<1];
vectort[2][N];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline void add(int u,int v){
++cnt;
a[cnt].to=v;
a[cnt].next=head[u];
head[u]=cnt;
}
inline void pre(int x,int fai){
f[++ind][0]=x;true_id[x]=ind;
for(int i=head[x];i;i=a[i].next){
int v=a[i].to;
if(v==fai)continue;
dep[v]=dep[x]+1;
pre(v,x);
f[++ind][0]=x;
}
}
inline int depmin(int x,int y){
return dep[x]true_id[y])swap(x,y);
int xi=true_id[x],yi=true_id[y];
int k=logi[yi-xi+1];
int lca=depmin(f[xi][k],f[yi-(1<=u)lasti+=query(0,fa[i],y-u)-query(1,i,y-u);
//这里请参考eleveni的神奇想法:
//宝石那题一层一层往上蹦着记录fa[i]对答案的贡献
//减去fa[i]已经被计算过的子树的贡献
}
cout<
2.2.3 P6626 [省选联考 2020 B 卷] 消息传递(简化版模板)
https://www.luogu.com.cn/problem/P6626
30pts:暴力+线段树
我执意要把一个父亲一个父亲蹦的代码搞上来,然后它TLE了……
#include
using namespace std;
const int N=1e5+10;
int T,n,m,cnt,head[N],dep[N],ans;
struct node{
int to,next;
}a[N<<1];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline void add(int u,int v){
++cnt;
a[cnt].to=v;
a[cnt].next=head[u];
head[u]=cnt;
}
inline void dfs(int x,int fai,int k){
dep[x]=dep[fai]+1;
if(dep[x]==k)++ans;
for(int i=head[x];i;i=a[i].next){
int v=a[i].to;
if(v==fai)continue;
dfs(v,x,k);
}
}
inline void solve1(){
for(int i=1;i<=m;i++){
ans=0;
int x,k;
x=read();k=read();
dfs(x,0,k+1);
cout<>1;
build(lson(x),l,mid);
build(rson(x),mid+1,r);
update(x);
}
inline int query(int x,int l,int r,int L,int R,int k){
if(l==r)return t[x].val==k;
if(l>=L&&r<=R){
if(t[x].valR)return 0;
int mid=(l+r)>>1;
int fin=0;
if(L<=mid)fin+=query(lson(x),l,mid,L,R,k);
if(R>mid)fin+=query(rson(x),mid+1,r,L,R,k);
return fin;
}
inline void dfs2(int x,int fai){
dep[x]=dep[fai]+1;
fa[x]=fai;
sizei[x]=1;
id_true[++ind]=x;
true_id[x]=ind;
for(int i=head[x];i;i=a[i].next){
int v=a[i].to;
if(v==fai)continue;
dfs2(v,x);
sizei[x]+=sizei[v];
}
}
inline void find(){
cout<<"tree "<=v+1)ans+=query(1,1,ind,v+1,vi,k);
u=ui,v=vi;
}
cout<
100pts:点分树
好家伙,连修改都不用,直接上来怼!
#include
using namespace std;
const int N=1e5+10;
int n,T,m,cnt,head[N],dep[N];
int tot,root,sizei[N],maxn[N],vis[N];
int fa[N],ind,f[N<<1][21],true_id[N],logi[N<<1];
struct node{
int to,next;
}a[N<<1];
vectort[2][N];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline void add(int u,int v){
++cnt;
a[cnt].to=v;
a[cnt].next=head[u];
head[u]=cnt;
}
inline void pre(int x,int fai){
dep[x]=dep[fai]+1;
f[++ind][0]=x;
true_id[x]=ind;
for(int i=head[x];i;i=a[i].next){
int v=a[i].to;
if(v==fai)continue;
pre(v,x);
f[++ind][0]=x;
}
}
inline void height(int x,int fai){
sizei[x]=1;maxn[x]=0;
for(int i=head[x];i;i=a[i].next){
int v=a[i].to;
if(v==fai||vis[v])continue;
height(v,x);
sizei[x]+=sizei[v];
maxn[x]=max(maxn[x],sizei[v]);
}
maxn[x]=max(maxn[x],tot-sizei[x]);
if(maxn[x]true_id[y])swap(x,y);
int xi=true_id[x],yi=true_id[y];
int k=logi[yi-xi+1];
int lca=depmin(f[xi][k],f[yi-(1<=k)fin=t[0][x][k];
for(int i=x;fa[i];i=fa[i]){
int disi=Dis(x,fa[i]);
if(disi>k||(k-disi)>sizei[fa[i]])continue;
fin+=t[0][fa[i]][k-disi];
if(sizei[i]>=k-disi)fin-=t[1][i][k-disi];
}
return fin;
}
inline void init(){
memset(true_id,0,sizeof(true_id));
memset(sizei,0,sizeof(sizei));
memset(head,0,sizeof(head));
memset(maxn,0,sizeof(maxn));
memset(dep,0,sizeof(dep));
memset(vis,0,sizeof(vis));
memset(fa,0,sizeof(fa));
memset(a,0,sizeof(a));
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
t[0][i].erase(t[0][i].begin(),t[0][i].end()),
t[1][i].erase(t[1][i].begin(),t[1][i].end());
cnt=ind=tot=0;
}
signed main(){
T=read();
while(T--){
init();
n=read();m=read();
for(int i=1;i