动态树分治

感受:

就是把分治结构变成树(并不需要真正建出,只需要记录父亲)

然后每个点维护子树到该点的信息,和子树到父亲点的信息

总体来说还是很模板的一个东西

题目大概分成两类:

(1)树上黑白点染色,问一个点到所有黑点的距离和

这种就是原来真正的树结构上信息修改,那么一般就是将修改的点在分治树上所在的链每个点维护的信息加加减减。

(2)另一种就是询问体现动态,比如距离某个点距离<=k的点的权值和

这种问题的突破点在于原树的信息是不改变的。所以我们可以在分治树上每个点维护一个vector数组来储存信息(有序)

分治树本身就是一种均摊的东西,树高为logn,每个点的信息最多出现logn次,所以这样每个点暴力sort均摊也是nlogn的

这样在处理询问的时候我们就可以二分更新答案了。

COGS2278 (第一种)

#include<bits/stdc++.h>
using namespace std;
int read(){
  int x=0,f=1;char ch=getchar();
  while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
  while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
  return x*f;
}
#define N 200005
#define ll long long
int n,m;
struct Node{
  int to,next,v;
}e[N<<1];
int tot,c[N],head[N],p[N][22],dep[N],Log[22];
int rt,sum,mx[N],sz[N],g[N],pos;
ll ans,Dis[N],Disf[N],num[N],dis[N];
bool vis[N];
void add(int x,int y,int z){
  e[++tot]=(Node){y,head[x],z};head[x]=tot;
  e[++tot]=(Node){x,head[y],z};head[y]=tot;
}
/*----------------------prepare--------------------------------*/
void dfs(int x,int f){
  p[x][0]=f;dep[x]=dep[f]+1;
  for(int i=head[x];i;i=e[i].next)if(e[i].to!=f){
  	dis[e[i].to]=dis[x]+1ll*e[i].v;dfs(e[i].to,x);
  }
}
void prepare(){
  for(int j=1;j<=20;j++)
    for(int i=1;i<=n;i++)p[i][j]=p[p[i][j-1]][j-1];
  Log[1]=0;
  for(int i=2;i<=20;i++)Log[i]=Log[i>>1]+1;
}
int LCA(int x,int y){
  if(dep[x]<dep[y])swap(x,y);
  for(int i=20;i>=0;i--)if(dep[x]-(1<<i)>=dep[y])x=p[x][i];
  if(x==y)return x;
  for(int i=20;i>=0;i--)
    if(p[x][i]!=p[y][i])x=p[x][i],y=p[y][i];
  return p[x][0];
}
ll d(int x,int y){return dis[x]+dis[y]-2*dis[LCA(x,y)];}
/*--------------------------动态树-----------------------------*/
void getroot(int x,int f){
  mx[x]=0;sz[x]=1;
  for(int i=head[x];i;i=e[i].next)if(!vis[e[i].to]&&e[i].to!=f){
    getroot(e[i].to,x);sz[x]+=sz[e[i].to];
    if(sz[e[i].to]>mx[x])mx[x]=sz[e[i].to];
  }
  if(sum-sz[x]>mx[x])mx[x]=sum-sz[x];
  if(mx[x]<mx[rt])rt=x;
}
void get_g(int x,int f){
  getroot(x,f);vis[rt]=1;g[rt]=f;int t=rt;
  for(int i=head[rt];i;i=e[i].next)if(!vis[e[i].to]){
    sum=sz[e[i].to];rt=0;get_g(e[i].to,t);
  }
}
void white(int x){
  num[x]--;Dis[x]-=d(x,pos);
  if(!g[x])return;
  Disf[x]-=d(g[x],pos);
  white(g[x]);
}
void black(int x){
  num[x]++;Dis[x]+=d(x,pos);
  if(!g[x])return;
  Disf[x]+=d(g[x],pos);
  black(g[x]);
}
void query(int x){
  ans+=num[x]*d(x,pos)+Dis[x];
  if(!g[x])return;
  ans-=(num[x]*d(g[x],pos)+Disf[x]);
  query(g[x]);
}
/*-------------------------------------------------------------*/
int main(){
  freopen("A_Tree.in","r",stdin);
  freopen("A_Tree.out","w",stdout);
  n=read();m=read();
  for(int i=1;i<n;i++){
  	int x=read(),y=read(),z=read();
  	add(x,y,z);
  }

  dfs(1,0);prepare();
  sum=n;rt=0;mx[0]=n;get_g(1,0);
//  for(int i=1;i<=n;i++)cout<<i<<‘ ‘<<g[i]<<endl;
  char s[5];
  while(m--){
  	scanf("%s",s);
  	int x=read();pos=x;
  	if(s[0]==‘Q‘){
  	  ans=0;query(x);printf("%lld\n",ans);
  	}
  	else{
  	  if(c[x])white(x);
  	  else black(x);
  	  c[x]^=1;
	}
  }
  return 0;
}

COGS 2258. [HZOI 2015]复仇的序幕曲 (第二种)

#include<bits/stdc++.h>
using namespace std;
int read(){
  int x=0,f=1;char ch=getchar();
  while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
  while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
  return x*f;
}
#define N 80005
struct Node{
  int to,next,v;
}e[N<<1];
int n,m,a[N];
int tot,head[N],dep[N],dis[N],p[N][22];
int sum,ans,pos,rt,mx[N],sz[N],g[N];
bool vis[N];
vector<pair<int,int> > Dis[N],Disf[N];
void add(int x,int y,int z){
  e[++tot]=(Node){y,head[x],z};head[x]=tot;
  e[++tot]=(Node){x,head[y],z};head[y]=tot;
}
/**********************************************************/
void dfs(int x,int f){
  dep[x]=dep[f]+1;p[x][0]=f;
  for(int i=head[x];i;i=e[i].next)if(e[i].to!=f){
    dis[e[i].to]=dis[x]+e[i].v;dfs(e[i].to,x);
  }
}
void prepare(){
  for(int j=1;j<=20;j++)
    for(int i=1;i<=n;i++)
      p[i][j]=p[p[i][j-1]][j-1];
}
int LCA(int x,int y){
  if(dep[x]<dep[y])swap(x,y);
  for(int i=20;i>=0;i--)if(dep[x]-(1<<i)>=dep[y])x=p[x][i];
  if(x==y)return x;
  for(int i=20;i>=0;i--)
    if(p[x][i]!=p[y][i])
      x=p[x][i],y=p[y][i];
  return p[x][0];
}
int d(int x,int y){return dis[x]+dis[y]-2*dis[LCA(x,y)];}
/**********************************************************/
void getroot(int x,int f){
  mx[x]=0;sz[x]=1;
  for(int i=head[x];i;i=e[i].next)if(e[i].to!=f&&!vis[e[i].to]){
    getroot(e[i].to,x);sz[x]+=sz[e[i].to];
    if(sz[e[i].to]>mx[x])mx[x]=sz[e[i].to];
  }
  if(sum-sz[x]>mx[x])mx[x]=sum-sz[x];
  if(mx[x]<mx[rt])rt=x;
}
void get_g(int x,int f){
  getroot(x,f);g[rt]=f;int t=rt;vis[t]=1;
  for(int i=head[rt];i;i=e[i].next)if(!vis[e[i].to]){
    sum=sz[e[i].to];rt=0;get_g(e[i].to,t);
  }
}
#define mp make_pair<int,int>
#define F first
#define S second
void update(int x){
  Dis[x].push_back(mp(d(x,pos),a[pos]));
  Disf[x].push_back(mp(d(g[x],pos),a[pos]));
  if(g[x]>0)update(g[x]);
}
int erfen(vector<pair<int,int> > &v,int lim){
  int l=0,r=v.size()-1,mid,tmp=-1;
  while(l<=r){
    mid=l+r>>1;
    if(v[mid].F<=lim)tmp=mid,l=mid+1;
    else r=mid-1;
  }
  if(tmp==-1)return 0;
  return v[tmp].S;
}
void query(int x,int lim){
  ans+=erfen(Dis[x],lim-d(pos,x));
  if(!g[x])return;
  ans-=erfen(Disf[x],lim-d(pos,g[x]));
  query(g[x],lim);
}
int main(){
  freopen("SS.in","r",stdin);
  freopen("SS.out","w",stdout);
  n=read();m=read();
  for(int i=1;i<=n;i++)a[i]=read();
  for(int i=1;i<n;i++){
    int x=read(),y=read(),z=read();
    add(x,y,z);
  }

  dfs(1,0);prepare();
  sum=n;mx[rt=0]=n;get_g(1,0);

  for(int i=1;i<=n;i++)pos=i,update(i);
  for(int i=1;i<=n;i++){
    sort(Dis[i].begin(),Dis[i].end());
    sort(Disf[i].begin(),Disf[i].end());
    for(int j=1;j<Dis[i].size();j++){
      Dis[i][j].S+=Dis[i][j-1].S;
      Disf[i][j].S+=Disf[i][j-1].S;
	}
  }

  while(m--){
    int x=read(),y=read();pos=x;ans=0;
    query(x,y);printf("%d\n",ans);
  }
  return 0;
}

  

HNOI2015 开店 (第二种)

还没写QAQ

时间: 2024-12-20 12:16:14

动态树分治的相关文章

【bzoj3924】[Zjoi2015]幻想乡战略游戏 动态树分治

题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了. 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决. 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来.在游戏中,幽香可能在空地上增加或者减少一些军队.同时,幽香可以在一个空地上放置一个补给站. 如果补给站在点u上,并

BZOJ 1095 ZJOI2007 Hide 捉迷藏 动态树分治+堆

题目大意:给定一棵树,一开始每个点都是黑点,多次改变某个点的状态或询问距离最远的两个黑点的距离 <珍爱生命远离STL可是我还是可耻地用了STL系列> 传说中的动态树分治...其实并没有那么神嘛= = ↑别听这傻瓜瞎说这货被STL卡了一天QAQ 我们把分治过程中遍历过的重心都连起来 上一层的重心链接下一层的重心 可以得到一棵新的树 下面我们开始讨论这棵新树 显然这棵树的高度不会超过O(logn) 然后我们每个节点开两个堆 第一个堆记录子树中所有节点到父亲节点的距离 第二个堆记录所有子节点的堆顶

【BZOJ3730】震波 动态树分治+线段树

[BZOJ3730]震波 Description 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动.接下来你需要在线处理M次操作:0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和.1 x y 表示第x个城市的价值变成了y.为了体现程序的在

【bzoj4012】[HNOI2015]开店 动态树分治+二分查找

题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面向什么样的人群.很神奇的是,幻想乡的地图是一个树形结构,幻想乡一共有 n个地方,编号为 1 到 n,被 n-1 条带权的边连接起来.每个地方都住着一个妖怪,其中第 i 个地方的妖怪年龄是 x_i.妖怪都是些比较喜欢安静的家伙,所以它们并不希望和很多妖怪相邻.所以这个树所有顶点的

BZOJ 3924 Zjoi2015 幻想乡战略游戏 动态树分治

题目大意:给定一棵树,每个点有一个点权,多次改变某个点的点权,多次查询带权重心到所有点的带权距离之和 此生无悔入东方,来世愿生幻想乡 首先我们考虑如何计算一个点到所有点的带权距离之和且支持修改 用动态树分治就好了嘛... 每个点记录子树中带权距离之和,以及权值之和,再在每个子树中记录一个需要减掉的版本 然后一直向上扫到根就能统计了 ↑这段话面对会写动态树分治的人,不会的先去切捉迷藏吧 然后就好搞了... 对于分治结构的每一个点,我们枚举它的出边 如果某条出边连向的点的距离之和小于当前点,那么答案

【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆

[BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋子都互相可达.游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯.在起初的时候,所有的灯都没有被打开.每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激

【BZOJ4372】烁烁的游戏 动态树分治+线段树

[BZOJ4372]烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠.皮皮鼠会被烁烁吸引,所以会一直待在节点上不动.烁烁很好奇,在当前时刻,节点u有多少个他的好朋友---皮皮鼠.大意:给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:Q x:询问x的点权.M x d w:将树上与节点x距离不超过d的节点的点权均加上w. In

动态树分治小结

传统的树分治,不能处理在线的询问. 我们可以把每次点分治的重心和它分割出的子树的重心连接,容易发现形成了一颗新的树. 这棵树有哪些性质呢?首先,树高不超过log(n),其次,一个节点原子树中的所有节点,依然在新树里它的子树中. 因为树高只有log(n),所以我们考虑从一个点出发的路径时,可以枚举它到新树中的根的每个节点作为lca,统计即可. 1095: [ZJOI2007]Hide 捉迷藏

BZOJ 4012 HNOI2015 开店 动态树分治+二分

题目大意:给定一棵树,每个点有一个颜色,多次询问颜色在[l,r]区间内的所有点与某个点之间的距离之和,强制在线 没记错的话这题我知道的有三种解法来着? (茴香豆的茴有四种写法泥萌知道嘛-? 1.线段树维护虚树 2.点分治+线段树 3.分块 第一种方法我不知道在线怎么搞= = (我并不知道怎么在虚树上进行点定位 第三种方法貌似内存过不去? 于是果断点分治+线段树 写完发现内存还是炸了= = O(nlog2n)的内存说什么也过不去啊= = 后来发现既然维护的是和不是最值那还要线段树干嘛= = 直接开