简介

动态点分治的思想:还不太清楚诶怎么办。

大概是通过降低树高来降低每次修改和询问的复杂度吧,还可以把树上一个连通块的信息统计到一个点(重心)上。具体实现方式和普通的静态点分治没有太大的区别,只是把点分治时递归到的每层重心用边连起来(当然不是在原树中直接连),构成一个叫做点分树(VPT)的东西,它其实就是个弟弟递归结构。

修改原树信息时(注意这里的修改一般是围绕一个结点进行的,但不一定是单点修改),可以在点分树上找到对应的结点,然后一路爬点分树的树边修改沿路结点的信息,询问的时候和修改差不多。

但是直接这样做会有些问题,容易发现,在点分树上的一对父子结点的担当区域是有交集的(其实就是父结点的担当区域包含子结点的),所以,为了去除重复部分对每次询问答案的影响,通常需要在每个结点处再维护一个这个结点担当区域对其点分树上父结点的贡献,爬树边时把它减去就行了。

看几道例题:

[BZOJ3730]震波

传送门

分析

点分树每个结点处维护两棵线段树,一棵存这个结点担当区域的结点对这个结点的贡献,另一个存这个结点担当区域对其父结点的贡献。

这份代码会TLE。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#define rin(i,a,b) for(register int i=(a);i<=(b);i++)
#define rec(i,a,b) for(register int i=(a);i>=(b);i--)
#define trav(i,a) for(register int i=head[(a)];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl; char buf[1<<23],*p1=buf,*p2=buf,obuf[1<<23],*O=obuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
inline 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<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
} const int MAXN=100005;
int n,m,ecnt,cog,head[MAXN],a[MAXN];
int id[MAXN],num[MAXN],pos[MAXN],dep[MAXN],st[25][MAXN<<1],tot,len;
int fa[MAXN],siz[MAXN],totsiz;
int root1[MAXN],root2[MAXN],lc[MAXN*200],rc[MAXN*200],sum[MAXN*200],loc,ql,qr,kk,tot2;
bool vis[MAXN];
struct Edge{
int to,nxt;
}e[MAXN<<1]; inline void add_edge(int bg,int ed){
ecnt++;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
head[bg]=ecnt;
} void dfs(int x,int pre,int depth){
dep[x]=depth;
id[x]=++tot;
num[tot]=x;
st[0][++len]=tot;
pos[x]=len;
trav(i,x){
int ver=e[i].to;
if(ver==pre) continue;
dfs(ver,x,depth+1);
st[0][++len]=id[x];
}
} inline void buildst(){
int lim=log2(len);
rin(i,1,lim) rin(j,1,len-(1<<i)+1)
st[i][j]=std::min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
} inline int lca(int x,int y){
int xx=pos[x],yy=pos[y];
if(xx>yy) std::swap(xx,yy);
int lim=log2(yy-xx+1);
return num[std::min(st[lim][xx],st[lim][yy-(1<<lim)+1])];
} inline int getdis(int x,int y){
return dep[x]+dep[y]-(dep[lca(x,y)]<<1);
} void getcog(int x,int pre){
siz[x]=1;
bool flag=1;
trav(i,x){
int ver=e[i].to;
if(ver==pre||vis[ver]) continue;
getcog(ver,x);
siz[x]+=siz[ver];
if(siz[ver]>totsiz/2) flag=0;
}
if(totsiz-siz[x]>totsiz/2) flag=0;
if(flag) cog=x;
} #define mid ((l+r)>>1)
int upd(int pre,int l,int r){
int o=pre;
if(!o) o=++tot2;
sum[o]+=kk;
if(l==r) return o;
if(loc<=mid) lc[o]=upd(lc[pre],l,mid);
else rc[o]=upd(rc[pre],mid+1,r);
return o;
} int query(int o,int l,int r){
if(!o) return 0;
if(ql<=l&&r<=qr) return sum[o];
int ret=0;
if(mid>=ql) ret+=query(lc[o],l,mid);
if(mid<qr) ret+=query(rc[o],mid+1,r);
return ret;
}
#undef mid void buildsgt(int x,int pre,int now){
loc=getdis(x,now)+1,kk=a[x];
root1[now]=upd(root1[now],1,n);
if(fa[now]){
loc=getdis(x,fa[now])+1,kk=a[x];
root2[now]=upd(root2[now],1,n);
}
siz[x]=1;
trav(i,x){
int ver=e[i].to;
if(ver==pre||vis[ver]) continue;
buildsgt(ver,x,now);
siz[x]+=siz[ver];
}
} void buildvpt(int x){
vis[x]=1;
buildsgt(x,0,x);
trav(i,x){
int ver=e[i].to;
if(vis[ver]) continue;
totsiz=siz[ver];
getcog(ver,x);
fa[cog]=x;
buildvpt(cog);
}
} inline int getans(int x,int y){
int now=x,ret=0;
while(1){
int curdis=getdis(x,now);
if(curdis<=y){
ql=1,qr=y-curdis+1;
ret+=query(root1[now],1,n);
}
if(!fa[now]) return ret;
curdis=getdis(x,fa[now]);
if(curdis<=y){
ql=1,qr=y-curdis+1;
ret-=query(root2[now],1,n);
}
now=fa[now];
}
} inline void modi(int x,int y){
int now=x;
while(1){
loc=getdis(x,now)+1,kk=y-a[x];
root1[now]=upd(root1[now],1,n);
if(!fa[now]){a[x]=y;return;}
loc=getdis(x,fa[now])+1,kk=y-a[x];
root2[now]=upd(root2[now],1,n);
now=fa[now];
}
} int main(){
n=read(),m=read();
rin(i,1,n) a[i]=read();
rin(i,2,n){
int u=read(),v=read();
add_edge(u,v);
add_edge(v,u);
}
dfs(1,0,1);
buildst();
totsiz=n;
getcog(1,0);
buildvpt(cog);
int lastans=0;
while(m--){
int opt=read();
if(opt==0){
int x=(read()^lastans),y=(read()^lastans);
lastans=getans(x,y);
printf("%d\n",lastans);
}
else{
int x=(read()^lastans),y=(read()^lastans);
modi(x,y);
}
}
return 0;
}

[BZOJ4372]烁烁的游戏

传送门

分析

怕和上一道题是一对。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,x) for(int i=head[(x)];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl; inline 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<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
} const int MAXN=100005;
int n,m,ecnt,head[MAXN];
int dep[MAXN],id[MAXN],num[MAXN],pos[MAXN],st[25][MAXN<<1],tot,len;
int root,cog,totsiz,fa[MAXN],siz[MAXN];
int root1[MAXN],root2[MAXN],lc[MAXN*200],rc[MAXN*200],sum[MAXN*200],tag[MAXN*200];
int loc,ql,qr,kk,tot2;
bool vis[MAXN];
struct Edge{
int to,nxt;
}e[MAXN<<1]; inline void add_edge(int bg,int ed){
ecnt++;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
head[bg]=ecnt;
} void dfs(int x,int pre,int depth){
dep[x]=depth;
id[x]=++tot;
num[tot]=x;
st[0][++len]=id[x];
pos[x]=len;
trav(i,x){
int ver=e[i].to;
if(ver==pre) continue;
dfs(ver,x,depth+1);
st[0][++len]=id[x];
}
} inline void buildst(){
int lim=log2(len);
rin(i,1,lim) rin(j,1,len-(1<<i)+1)
st[i][j]=std::min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
} inline int lca(int x,int y){
int xx=pos[x],yy=pos[y];
if(xx>yy) std::swap(xx,yy);
int lim=log2(yy-xx+1);
return num[std::min(st[lim][xx],st[lim][yy-(1<<lim)+1])];
} inline int getdis(int x,int y){
return dep[x]+dep[y]-(dep[lca(x,y)]<<1);
} void getcog(int x,int pre){
siz[x]=1;
bool flag=1;
trav(i,x){
int ver=e[i].to;
if(ver==pre||vis[ver]) continue;
getcog(ver,x);
siz[x]+=siz[ver];
if(siz[ver]>totsiz/2) flag=0;
}
if(totsiz-siz[x]>totsiz/2) flag=0;
if(flag) cog=x;
} void getsiz(int x,int pre){
siz[x]=1;
trav(i,x){
int ver=e[i].to;
if(ver==pre||vis[ver]) continue;
getsiz(ver,x);
siz[x]+=siz[ver];
}
} void buildvpt(int x){
vis[x]=1;
getsiz(x,0);
trav(i,x){
int ver=e[i].to;
if(vis[ver]) continue;
totsiz=siz[ver];
getcog(ver,x);
fa[cog]=x;
buildvpt(cog);
}
} #define mid ((l+r)>>1)
int upd(int pre,int l,int r){
int o=pre;
if(!o) o=++tot;
sum[o]+=(std::min(qr,r)-std::max(ql,l)+1)*kk;
if(ql<=l&&r<=qr){
tag[o]+=kk;
return o;
}
if(mid>=ql) lc[o]=upd(lc[pre],l,mid);
if(mid<qr) rc[o]=upd(rc[pre],mid+1,r);
return o;
} int query(int o,int l,int r){
if(l==r) return sum[o];
if(loc<=mid) return query(lc[o],l,mid)+tag[o];
else return query(rc[o],mid+1,r)+tag[o];
}
#undef mid inline int getans(int x){
int now=x,ret=0;
while(1){
loc=getdis(x,now)+1;
ret+=query(root1[now],1,n);
if(!fa[now]) return ret;
loc=getdis(x,fa[now])+1;
ret-=query(root2[now],1,n);
now=fa[now];
}
} inline void modi(int x,int y,int z){
int now=x;
while(1){
int curdis=getdis(x,now);
if(curdis<=y){
ql=1,qr=y-curdis+1,kk=z;
root1[now]=upd(root1[now],1,n);
}
if(!fa[now]) return;
curdis=getdis(x,fa[now]);
if(curdis<=y){
ql=1,qr=y-curdis+1,kk=z;
root2[now]=upd(root2[now],1,n);
}
now=fa[now];
}
} int main(){
n=read(),m=read();
rin(i,2,n){
int u=read(),v=read();
add_edge(u,v);
add_edge(v,u);
}
dfs(1,0,1);
buildst();
totsiz=n;
getcog(1,0);
root=cog;
buildvpt(cog);
while(m--){
char opt=getchar();
while(!isalpha(opt)) opt=getchar();
if(opt=='Q'){
int x=read();
printf("%d\n",getans(x));
}
else{
int x=read(),y=read(),z=read();
modi(x,y,z);
}
}
return 0;
}

[BZOJ3924][ZJOI2015]幻想乡战略游戏

传送门

分析

对点分树的每个结点维护\(3\)个值,\(sum1[x],sum2[x],sum3[x]\),分别表示\(x\)担当区域对\(x\)的贡献,对\(fa[x]\)的贡献,以及权值和。

我们可以从点分树的根结点出发,根据当前结点的答案和其点分树上子结点的答案,来推出答案在当前结点还是在其在点分树上的某个子结点的担当区域内,不断递归下去即可得到答案。(这里结点\(x\)的答案指的是\(\sum val[y] \times dist(x,y)\))。

如何求某个结点的答案?还是爬点分树就可以了,在每一层:

\[ans+=sum1[x]-sum2[x]+(sum3[fa[x]]-sum3[x])*dist(fa[x],AskedVertex)
\]

代码

BZOJ Rank Last代码,欢迎各位dalao嘲讽。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <vector>
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl; inline 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<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
} const int MAXN=100005;
int n,q,ecnt,head[MAXN];
int id[MAXN],num[MAXN],pos[MAXN],st[25][MAXN<<1],tot,len;
int root,cog,totsiz,siz[MAXN],fa[MAXN];
LL dep[MAXN],sum1[MAXN],sum2[MAXN],sum3[MAXN];
bool vis[MAXN];
std::vector<int> vec[MAXN],vec2[MAXN];
struct Edge{
int to,nxt;
LL w;
}e[MAXN<<1]; inline void add_edge(int bg,int ed,LL val){
ecnt++;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
e[ecnt].w=val;
head[bg]=ecnt;
} void dfs(int x,int pre,LL depth){
dep[x]=depth;
id[x]=++tot;
num[tot]=x;
st[0][++len]=id[x];
pos[x]=len;
trav(i,x){
int ver=e[i].to;
if(ver==pre) continue;
dfs(ver,x,depth+e[i].w);
st[0][++len]=id[x];
}
} inline void buildst(){
int lim=log2(len);
rin(i,1,lim) rin(j,1,len-(1<<i)+1)
st[i][j]=std::min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
} inline int lca(int x,int y){
int xx=pos[x],yy=pos[y];
if(xx>yy) std::swap(xx,yy);
int lim=log2(yy-xx+1);
return num[std::min(st[lim][xx],st[lim][yy-(1<<lim)+1])];
} inline LL getdis(int x,int y){
return dep[x]+dep[y]-(dep[lca(x,y)]<<1);
} void getcog(int x,int pre){
siz[x]=1;
bool flag=1;
trav(i,x){
int ver=e[i].to;
if(ver==pre||vis[ver]) continue;
getcog(ver,x);
siz[x]+=siz[ver];
if(siz[ver]>totsiz/2) flag=0;
}
if(totsiz-siz[x]>totsiz/2) flag=0;
if(flag) cog=x;
} void getsiz(int x,int pre){
siz[x]=1;
trav(i,x){
int ver=e[i].to;
if(ver==pre||vis[ver]) continue;
getsiz(ver,x);
siz[x]+=siz[ver];
}
} void buildvpt(int x){
vis[x]=1;
getsiz(x,0);
trav(i,x){
int ver=e[i].to;
if(vis[ver]) continue;
totsiz=siz[ver];
getcog(ver,x);
fa[cog]=x;
vec[x].push_back(cog);
vec2[x].push_back(ver);
buildvpt(cog);
}
} inline void upd(int x,LL y){
int now=x;
while(1){
sum1[now]+=y*getdis(x,now);
sum3[now]+=y;
if(!fa[now]) return;
sum2[now]+=y*getdis(x,fa[now]);
now=fa[now];
}
} inline LL getv(int x){
int now=x;LL ret=0;
while(1){
ret+=sum1[now];
if(!fa[now]) return ret;
ret+=(sum3[fa[now]]-sum3[now])*getdis(x,fa[now]);
ret-=sum2[now];
now=fa[now];
}
} int query(int x){
LL now=getv(x);
rin(i,0,(int)vec[x].size()-1){
int ver=vec2[x][i];
if(getv(ver)<now) return query(vec[x][i]);
}
return x;
} int main(){
n=read(),q=read();
rin(i,2,n){
int u=read(),v=read();LL w=read();
add_edge(u,v,w);
add_edge(v,u,w);
}
dfs(1,0,0);
buildst();
totsiz=n;
getcog(1,0);
root=cog;
buildvpt(cog);
while(q--){
int x=read();LL y=read();
upd(x,y);
printf("%lld\n",getv(query(root)));
}
return 0;
}

[BZOJ1095][ZJOI2007]Hide 捉迷藏

还没做。

最新文章

  1. linux vi基本操作
  2. Winform-DataGridView 实现如Excel的粘贴复制
  3. django字段设置null和blank的区别
  4. JSP的编译指令
  5. Android ListVIew 详解(一)
  6. KVO监听数组的变化
  7. Unity3D Log 收集机制
  8. hdu 1329 Hanoi Tower Troubles Again!
  9. 瞬间从IT屌丝变大神——注释规则
  10. (转)XML CDATA是什么?
  11. ListView与CheckBox组合实现单选
  12. arrowTip 提示
  13. php框架
  14. JavaScript高级程序设计---学习笔记(三)
  15. Aliase_小白学Python_Day0_前言
  16. AQS 框架之 Unsafe 源码详解
  17. POJ 放苹果问题(递归)
  18. vue中watch检测到不到对象属性的变化的解决方法
  19. Sublime text 3 格式化代码 插件
  20. mysql索引优化-order/group

热门文章

  1. Canvas入门06-线段与像素边界
  2. [LeetCode] 203. 移除链表元素
  3. MySQL explain,Extra分析(转)
  4. http-proxy-middleware
  5. Cocos2d-x-javaScript 的webSocket的代码
  6. 计算机系统结构总结_Memory Hierarchy and Memory Performance
  7. spring data jpa Specification 复杂查询+分页查询
  8. mysql,oracle,sql server数据库默认的端口号,端口号可以为负数吗?以及常用协议所对应的缺省端口号
  9. 基于Nginx+nginx-rtmp-module+ffmpeg搭建rtmp、hls流媒体服务器
  10. 将Docker主机数据挂在到容器中