模板:点分治点分树

文章目录

  • 前言
  • 点分治
    • 背景
    • 解析
    • 代码
  • 点分树
    • 情境
  • 代码
  • thanks for reading!

所谓点分治,就是把所有的点分开来治

(逃)
(应广大观众要求,开篇废话改回原风格qwq)

前言

很神奇的算法。
没有引入任何新的知识,却把时间复杂度降到了一个很好的等级。
感觉点分治模板本身当成一道题来做也不过分。

对于点分树,感觉它的另一个名字也很不错:动态点分治。
通常可以解决一些与树原形态联系较小的问题(如距离等)。

点分治

背景

给定一棵树,求树上距离不超过k的点对数目
n≤105n\leq10^5n105

传送门

解析

考虑点分治

分治的普遍特征是把总问题分解成若干子问题递归求解,再合并答案
本题中,不难想到按照重心把子树分成若干个联通块进行递归,这样划分次数不会超过log级别
现在的重点就是,如何合并答案
首先各个联通块的答案肯定要加起来
剩下还没统计到的就是 经过重心(设为x) 的合法路径了

考虑把所有点dfs一遍算出深度,sort一下后利用双指针就可以线性求出来

比较敏锐的童鞋很显然会发现我这纯粹就是胡说八道,因为这样还会重复统计到在同一个子树内的答案
所以我们要把在同一个子树内的答案容斥掉
代码实现上,计算答案和容斥部分可以通过传参的不同用一个函数进行
具体实现很优雅,看代码应该能更好的理解

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=4e4+100;
const int M=2e5+10500;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}int n,m;
struct node{int to,nxt,w;
}p[N<<1];
int fi[N],cnt;
inline void addline(int x,int y,int w){p[++cnt]=(node){y,fi[x],w};fi[x]=cnt;return;
}int siz[N],mx[N],dis[N],tot,rt,S,ans;
bool vis[N];void find(int x,int fa){siz[x]=1;mx[x]=0;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(vis[to]||to==fa) continue;find(to,x);siz[x]+=siz[to];mx[x]=max(mx[x],siz[to]);}mx[x]=max(mx[x],S-siz[x]);if(!rt||mx[x]<mx[rt]) rt=x;return;
}void getdis(int x,int fa,int d){dis[++tot]=d;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==fa||vis[to]) continue;getdis(to,x,d+p[i].w);}return;
}int calc(int x,int d){tot=0;getdis(x,0,d);					sort(dis+1,dis+1+tot);int l=1,r=tot,res(0);while(l<r){if(dis[l]+dis[r]<=m) res+=r-l,l++;else --r;}return res;
}void solve(int x){S=siz[x];rt=0;find(x,0);x=rt;ans+=calc(x,0);vis[x]=1;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(vis[to]) continue;ans-=calc(to,p[i].w);}for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(vis[to]) continue;solve(to);}return;
}int main(){
#ifndef ONLINE_JUDGE//freopen("a.in","r",stdin);//freopen("a.out","w",stdout);
#endifmemset(fi,-1,sizeof(fi));cnt=-1;n=read();for(int i=1;i<n;i++){int x=read(),y=read(),w=read();addline(x,y,w);addline(y,x,w);}m=read();S=n;find(1,0);siz[rt]=n;solve(rt);printf("%d\n",ans);return 0;
}
/*
4 4 1 2 3 4 7
*/

点分树

情境

给出一棵点带权边无权的树,要求你支持在线回答到某个点距离不超过 kkk 的点对权值和,或者修改某个点对权值。

其实所有的分治算法都形成了一个树形结构,那么这里我们考虑把之前的点分治的结构显性的建出来。
具体的,每一层的重心都是下一层重心的父亲
这样我们就建出来点分树,它的树高是 O(log⁡n)O(\log n)O(logn) 的。

对于每次对 xxx 结点的询问,我们就先统计 xxx 自己处的信息(距离不超过 kkk 的权值和),然后不停往上跳 fafafa,然后统计 fafafa 的信息(与 fafafa 距离不超过 k−dis(fa,x)k-dis(fa,x)kdis(fa,x) 的权值和)。
那么对应的,我们就需要每个结点维护两个数据结构:一个维护自己的信息,一个维护对父亲的贡献。(这是一个很重要的套路!)
具体的说,维护两个树状数组,一个维护点分树上的子树内到自己距离为 xxx 的权值和,一个维护点分树上的子树内到父亲距离为 xxx 的权值和。

然而,我们是无法对每个结点开大小为 O(n)O(n)O(n) 的数组的,所以我们考虑使用 vector,只开到 O(sizx)O(siz_x)O(sizx) 大小,这样空间复杂度就是 O(nlog⁡n)O(n\log n)O(nlogn) 的。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define OK printf("ok\n")
#define debug(...) fprintf(stderr,__VA_ARGS__)
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
const int N=2e5+100;
const int inf=1e9+100;
int n,m;
struct node{int to,nxt;
}p[N<<1];
int fi[N],cnt;
inline void addline(int x,int y){p[++cnt]=(node){y,fi[x]};fi[x]=cnt;return;
}
int dep[N],q[N<<1],tot,pl[N];
void dfs0(int x,int f){dep[x]=dep[f]+1;q[++tot]=x;pl[x]=tot;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;dfs0(to,x);q[++tot]=x;}return;
}
int Min(int x,int y){return dep[x]<dep[y]?x:y;
}
int lg[N<<1],mn[N<<1][20],mi[20];
void init(){dfs0(1,0);lg[0]=-1;for(int i=1;i<=tot;i++) lg[i]=lg[i>>1]+1;mi[0]=1;for(int i=1;i<=lg[tot];i++) mi[i]=mi[i-1]<<1;for(int i=1;i<=tot;i++) mn[i][0]=q[i];for(int k=1;k<=lg[tot];k++){for(int i=1;i+mi[k]-1<=tot;i++) mn[i][k]=Min(mn[i][k-1],mn[i+mi[k-1]][k-1]);}return;
}
inline int Lca(int x,int y){x=pl[x];y=pl[y];if(x>y) swap(x,y);int k=lg[y-x+1];//printf("  k=%d\n",k);return Min(mn[x][k],mn[y-mi[k]+1][k]);
}
inline int Dis(int x,int y){int lca=Lca(x,y);//printf("(%d %d) lca=%d dis=%d\n",x,y,lca,dep[x]+dep[y]-2*dep[lca]);return dep[x]+dep[y]-2*dep[lca];
}
vector<int>f[2][N];
int w[N],top[N];
int rt,mnn,siz[N],S,son[N];
bool vis[N];
int o;
void findrt(int x,int f){siz[x]=1;son[x]=0;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f||vis[to]) continue;findrt(to,x);siz[x]+=siz[to];son[x]=max(son[x],siz[to]);}son[x]=max(son[x],S-siz[x]);if(mnn>son[x]){mnn=son[x];rt=x;}return;
}
int tim;
int solve(int x,int nS){//if(tim%1000==0) debug("%d\n",x);//printf("??\n");S=nS;mnn=inf;findrt(x,0);x=rt;vis[x]=1;siz[x]=S+1;f[0][x].resize(siz[x]+1);f[1][x].resize(siz[x]+1);for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(vis[to]) continue;int tmp=solve(to,nS-son[to]);top[tmp]=x;}return x;
}
void add(int op,int x,int p,int w){++p;for(;p<=siz[x];p+=p&-p){f[op][x][p]+=w;//printf("%d\n",p);}return;
}
int ask(int op,int x,int p){if(p<0) return 0;++p;p=min(p,siz[x]);int res(0);for(;p;p-=p&-p) res+=f[op][x][p];return res;
}
void upd(int x,int w){//w:deltafor(int i=x;i;i=top[i]) add(0,i,Dis(x,i),w);for(int i=x;top[i];i=top[i]) add(1,i,Dis(x,top[i]),w);return;
}
int query(int x,int d){int ans=ask(0,x,d);//printf("ans=%d\n",ans);for(int i=x;top[i];i=top[i]){int nd=d-Dis(x,top[i]);//printf("top=%d nd=%d ans+=%d-%d=%d\n",top[x],)ans+=ask(0,top[i],nd)-ask(1,i,nd);}return ans;
}
signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifmemset(fi,-1,sizeof(fi));cnt=-1;n=read();m=read();for(int i=1;i<=n;i++) w[i]=read();for(int i=1;i<n;i++){int x=read(),y=read();addline(x,y);addline(y,x);}init();	solve(1,n);/*mnn=inf;S=n;findrt(1,0);mnn=0;findrt(rt,0);	solve(rt);*/	//return 0;for(int i=1;i<=n;i++) upd(i,w[i]);//for(int i=1;i<=n;i++) printf("i=%d siz=%d top=%d\n",i,siz[i],top[i]);int lst(0);for(int i=1;i<=m;i++){int op=read(),x=read()^lst,y=read()^lst;if(op==1){upd(x,y-w[x]);w[x]=y;}else{printf("%d\n",lst=query(x,y));}}return 0;
}
/*
7 1
1 2 3 4 5 6 7
1 2
2 3
2 4
4 5
4 6
1 7
0 7 1
*/

thanks for reading!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317423.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.NET Core 3 Preview 2发布,C#8更强大的模式匹配

.NET Core 3 Preview 2 发布了&#xff0c;此版本主要带来了 C# 8 相关的新功能&#xff0c;C# 8 Preview 2 是 .NET Core 3 SDK 的一部分。C# 8 中使用模式进行更多操作&#xff0c;主要特性包括&#xff1a;using 声明改变需要缩进代码的方式&#xff0c;现在可以编写以下代码…

Loj#2474-「2018 集训队互测 Day 3」北校门外的未来【LCT】

正题 题目链接:https://loj.ac/p/2474 题目大意 开始有一个只有点111的图&#xff0c;一个点xxx能走到点yyy当且仅当路径(x,y)(x,y)(x,y)之间&#xff08;不包括x,yx,yx,y&#xff09;不存在编号比xxx或yyy要大的节点。有mmm次操作&#xff1a; 新建一个编号为yyy的节点和xx…

CF407 E. k-d-sequence(线段树+单调栈)

文章目录CF407 E. k-d-sequenceproblemsolutioncodeCF407 E. k-d-sequence problem solution special case&#xff0c;d0d0d0&#xff0c;相当于寻找最长的一段数字相同的区间 other case&#xff0c;如果要满足公差为ddd等差序列 区间内每个数在模ddd意义下同余每个数互不…

D. Binary Literature

D. Binary Literature 题意&#xff1a; 给三个长度为2 * n的01串&#xff0c;让你构造一个长度小于3 * n的字符串&#xff0c;使得这个串至少包含两个01串 题解&#xff1a; 很巧妙的构造题 三个指针分别指向三个串&#xff0c;因为是01串&#xff0c;所以一定存在两个字符…

安逸:鼠绘《诗与远方》

【作品名称】《诗与远方》【作者介绍】徐安&#xff08;笔名安逸&#xff0c;常州&#xff09;&#xff0c;PPT专家&#xff0c;鼠绘专家。平面设计专业&#xff0c;6年PPT设计经验&#xff1b;历届江苏省PPT制作大赛一等奖获得者&#xff0c;PA口袋动画重要合作人。PPT动画制作…

洛谷P4292:重建计划(点分治、单调队列)

解析 第一眼&#xff1a;Wow这么水的黑&#xff1f;&#xff1f; 然后写了一发二分套线段树的3log代码上去 T到飞起&#xff0c;只有40… 无奈瞅了一眼标签&#xff1a;单调队列 对啊 于是又写了一个上去 20 … 好啊 然后就摆烂了 qwq 果然黑题没有一个好东西 一个关键的思…

E. Colorings and Dominoes(未解决)

E. Colorings and Dominoes 题意&#xff1a; n * m的格子&#xff0c;分为黑白格子&#xff0c;白格子可以染成蓝色或者红色&#xff0c;一个1 * 2的多米诺骨牌&#xff0c;可以覆盖两个连续的水平的红色格子或者两个连续的竖着的蓝色格子&#xff0c;对于一个染色方案&…

[HNOI2016]网络(树链剖分+线段树+大根堆)

[HNOI2016]网络 problem solution 另辟蹊径&#xff0c;不把交互请求赋在新增路径上&#xff0c;反而把交互请求赋在树上除去该请求路径覆盖点的其它点上 显然&#xff0c;路径问题树剖是非常可以的、 那么一个点上的信息就表示所有不经过该点的交互请求&#xff0c;用堆…

P4557-[JSOI2018]战争【凸包,闵可夫斯基和】

正题 题目连接:https://www.luogu.com.cn/problem/P4557 题目大意 给出两个点集A,BA,BA,B&#xff0c;qqq次询问给出一个向量vvv&#xff0c;询问将BBB中所有点加上向量vvv后两个集合的凸包是否有交。 1≤n,m,q≤1051\leq n,m,q\leq 10^51≤n,m,q≤105 解题思路 闵可夫斯基和…

IdentityServer4实战 - JWT Token Issuer 详解

一.前言本文为系列补坑之作&#xff0c;拖了许久决定先把坑填完。下文演示所用代码采用的 IdentityServer4 版本为 2.3.0&#xff0c;由于时间推移可能以后的版本会有一些改动&#xff0c;请参考查看&#xff0c;文末附上Demo代码。本文所诉Token如无特殊说明皆为 JWT Token。众…

P3834 【模板】可持久化线段树 2(整体二分做法)

P3834 【模板】可持久化线段树 2&#xff08;主席树&#xff09; 我们详细讲讲这个整体二分如何求区间第k小 我们都知道二分可以求出区间里某个想要的值&#xff0c;如果有很多询问&#xff0c;我们对每个询问都进行二分&#xff0c;复杂度就是O(QNlog(1e9))铁超&#xff0c;那…

YBTOJ洛谷P3292:幸运数字(线性基、点分治/倍增)

解析 虽然使用三个log的倍增算法艹过去了 但是我们还是来聊聊正解吧 考虑点分治 对于当前的根&#xff0c;dfs求出联通块内每个点到当前根的线性基 一条路径的答案应该在路径出现上第一个成为根的点时统计到 具体来说&#xff0c;就是路径的两端点在同一个solve函数的不同子树…

AGC053E-More Peaks More Fun【计数】

正题 题目链接:https://atcoder.jp/contests/agc053/tasks/agc053_e 题目大意 给出nnn个二元组(ai,bi)(a_i,b_i)(ai​,bi​)&#xff0c;求有多少个1∼n1\sim n1∼n的排列ppp满足&#xff1a; 你可以将一些(ai,bi)(a_i,b_i)(ai​,bi​)变为(bi,ai)(b_i,a_i)(bi​,ai​)定义序…

「JOISC 2020 Day4」治疗计划(线段树+dijkstra最短路)

「JOISC 2020 Day4」治疗计划 description solution 设dpi:1−Ridp_i:1-R_idpi​:1−Ri​ 都能被救治成功的最小花费 两个治疗方案[Li,Ri],[Lj,Rj][L_i,R_i],[L_j,R_j][Li​,Ri​],[Lj​,Rj​]能够合并成完整的健康区间的条件为Ri−Lj1≥∣Ti−Tj∣R_i-Lj1\ge |T_i-T_j|Ri​…

胡浩:人人能学的AI《从零开始机器学习》苏州.NET俱乐部课程分享

【课程名称】《从零开始机器学XI》【老师介绍】胡浩&#xff0c;微软最有价值专家&#xff08;MVP&#xff0c;十余届多方向&#xff09;&#xff0c;微软技术大会讲师。云、数据中心基础架构、全栈虚拟化、企业移动管理等领域的架构师及顾问。AI/ML等新技术的爱好者&#xff0…

整体二分例题

参考oi wiki 引入&#xff1a; 有一部分题可以使用二分的办法来解决。但是当这种题目有多次询问且每次询问我们对每个查询都直接二分&#xff0c;可能会收获一个 TLE。这时候我们就会用到整体二分。整体二分的主体思路就是把多个查询一起解决。&#xff08;所以这是一个离线算…

P8338-[AHOI2022]排列【质因数分解】

正题 题目链接:https://www.luogu.com.cn/problem/P8338 题目大意 给出一个排列pip_ipi​&#xff0c;定义ai0i,aikapik−1a_i^0i,a_i^ka_{p_i}^{k-1}ai0​i,aik​api​k−1​。 对于排列PPP&#xff0c;定义F(P)F(P)F(P)表示最小的一个正整数kkk满足Pk1PP^{k1}PPk1P。 定义…

CF1100F Ivan and Burgers(线性基)

解析 做幸运数字的时候逛题解区爬过来的 挺妙的 把所有询问离线下来&#xff0c;按右端点排序 贪心的让最高位更高的向量出现的尽可能向右 实现上可以把线性基里的向量和当前的数swap来实现 代码就非常好写了 代码 #include<bits/stdc.h> using namespace std; #defi…

[APIO2013]机器人(DP+SPFA最短路)

[APIO2013]机器人 description solution dpl,r,i,j:dp_{l,r,i,j}:dpl,r,i,j​: 在(i,j)(i,j)(i,j)位置合并编号为[l,r][l,r][l,r]区间内的所有机器人的最小花费 toi,j,k:to_{i,j,k}:toi,j,k​: 从(i,j)(i,j)(i,j)以kkk方向推机器人最终停止的位置&#xff0c;用dfs记忆化搜索…

IdentityServer4实战 - 与API单项目整合

一.前言我们在实际使用 IdentityServer4 的时候&#xff0c;可能会在使用 IdentityServer4 项目添加一些API&#xff0c;比如 找回密码、用户注册、修改用户资料等&#xff0c;这些API与IdentityServer4怎么共存在一个项目呢&#xff1f;二.整合1.首先在 Startup.cs 中添加 Ide…