首页 > 其他分享 >点分治

点分治

时间:2025-01-07 12:33:21浏览次数:1  
标签:nxt typedef sz int 分治 vs now

更新日志 2025/01/07:开工。

概念

点分治,通常用于处理大规模的树上路径信息问题。

思路

我们将原问题划分为多种,对于每个节点,统计经过这个节点且位于这棵子树内的路径答案。

为了缩减复杂度,对于每一棵子树,我们都找到它的重心,以重心为新根在子树内进行操作。

找重心示例:

int cnt,sz[N];//当前处理的部分总节点数,当前节点内节点数
void getsiz(int now,int fid){
    sz[now]=1;cnt++;
    for(auto e:vs[now]){
        int nxt=e.fir;
        if(nxt!=fid&&!ok[nxt]){
            getsiz(nxt,now);
            sz[now]+=sz[nxt];
        }
    }
}

int rot;//重心
int f[N];//最大子树大小
void getrot(int now,int fid){
    f[now]=cnt-sz[now];
    for(auto e:vs[now]){
        int nxt=e.fir;
        if(nxt!=fid&&!ok[nxt]){
            getrot(nxt,now);
            chmax(f[now],sz[nxt]);
        }
    }
    if(f[now]<f[rot])rot=now;
}

void calc(int rt){
    cnt=0;getsiz(rt,rt);//获取大小
    rot=0;f[0]=inf;getrot(rt,rt);//获取重心
    /*一些操作*/
}

(重心就是最大子树大小最小的。)

通常情况下,我们有需要去清空一些数组。为了保证复杂度正确,我们把修改过的点存到队列里,最后清空时一个一个取出归零。

更新完一个节点后,其每一棵子树都是独立的,分别递归即可。注意判断那个节点是否已经作为重心被操作过。

例题

点分治

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef __int128 i128;
typedef double db;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<int,ll> pil;
typedef pair<ll,int> pli;
template <typename Type>
using vec=vector<Type>;
template <typename Type>
using grheap=priority_queue<Type>;
template <typename Type>
using lrheap=priority_queue<Type,vector<Type>,greater<Type> >;
#define fir first
#define sec second
#define pub push_back
#define pob pop_back
#define puf push_front
#define pof pop_front
#define chmax(a,b) a=max(a,b)
#define chmin(a,b) a=min(a,b)
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define per(i,x,y) for(int i=x;i>=y;i--)

const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;

const int N=1e4+5,M=105,K=1e7+5;

int n,m;
vec<pil> vs[N];

int ask[M];bool ans[M];

bool ok[N];

int cnt,sz[N];
void getsiz(int now,int fid){
    sz[now]=1;cnt++;
    for(auto e:vs[now]){
        int nxt=e.fir;
        if(nxt!=fid&&!ok[nxt]){
            getsiz(nxt,now);
            sz[now]+=sz[nxt];
        }
    }
}

int rot;
int f[N];
void getrot(int now,int fid){
    f[now]=cnt-sz[now];
    for(auto e:vs[now]){
        int nxt=e.fir;
        if(nxt!=fid&&!ok[nxt]){
            getrot(nxt,now);
            chmax(f[now],sz[nxt]);
        }
    }
    if(f[now]<f[rot])rot=now;
}

bool st[K];
int que[N],top;
void getdis(int now,int fid,int dis){
    if(dis>=K)return;
    que[++top]=dis;
    for(auto e:vs[now]){
        int nxt=e.fir,val=e.sec;
        if(nxt!=fid&&!ok[nxt]){
            getdis(nxt,now,dis+val);
        }
    }
}

void calc(int rt){
    cnt=0;getsiz(rt,rt);
    rot=0;f[0]=inf;getrot(rt,rt);
    top=0;que[++top]=0;st[0]=1;
    for(auto e:vs[rot]){
        int nxt=e.fir,val=e.sec;
        if(ok[nxt])continue;
        int i=top;getdis(nxt,rot,val);
        rep(q,1,m)if(!ans[q]){
            rep(j,i+1,top){
                if(ask[q]>=que[j]&&st[ask[q]-que[j]]){
                    ans[q]=1;
                    break;
                }
            }
        }
        rep(j,i+1,top)st[que[j]]=1;
    }
    while(top)st[que[top--]]=0;
    ok[rot]=1;
    for(auto e:vs[rot]){
        int nxt=e.fir;
        if(!ok[nxt])calc(nxt);
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    rep(i,2,n){
        int a,b,c;cin>>a>>b>>c;
        vs[a].pub({b,c});
        vs[b].pub({a,c});
    }
    rep(i,1,m)cin>>ask[i];
    calc(1);
    rep(i,1,m)cout<<(ans[i]?"AYE\n":"NAY\n");
    return 0;
}

标签:nxt,typedef,sz,int,分治,vs,now
From: https://www.cnblogs.com/HarlemBlog/p/18657401

相关文章

  • 分治杂记
    分治杂记分治(DivideandConquer),就是把一个复杂的问题分成若干子问题,分别求解。本质是缩小了问题的规模。普通的分治[ABC373G]NoCrossMatching给定平面上的\(n\)个黑点和\(n\)个白点,构造一种方案,将黑白点两两匹配并连线段,使得任意两条线段不相交。\(n\leq100\),保......
  • 深入了解分治 FFT
    问题提出算法应用于问题,分治FFT的出现是为了解决这样一个问题:给定序列\(g_{1\dotsn-1}\),求序列\(f_{0\dotsn-1}\)。其中\(f_i=\sum_{j=1}^if_{i-j}g_j\),边界为\(f_0=1\)。具体可以见【模板】分治FFT-洛谷对于这个问题我们要求做到\(\Theta(n\log^2n)\)的......
  • 【优选算法 & 分治】深入理解分治算法:分治算法入门小专题详解
             快速排序算法   (1)快速排序法       (2) 快排前后指针     (3)快排挖坑法   颜色分类  题目解析    算法原理   算法原理和移动零非常相似  简述移动零的算法原理   ......
  • [学习笔记] 根号分治
    https://www.cnblogs.com/guanlexiangfan/p/15553329.htmlhttps://blog.csdn.net/qq_35684989/article/details/127190872放一下讲得比较好的根号分治。根号分治,一般将数据分为\(a<\sqrtn\)的与\(a>\sqrtn\)的进行分类讨论。一般可以配合预处理将\(O(n^2)\)的做法优化......
  • 分治策略——算法学习(二)
    分治策略——算法学习(二)前言在算法设计的世界中,分治策略(DivideandConquer)是一种极具魅力的思想,它通过将复杂问题拆解为多个规模较小但结构类似的子问题,从而以递归的方式解决问题。这种策略不仅高效而且直观,为许多经典算法的诞生奠定了基础,如快速排序(QuickSort)、归并排序(Merg......
  • 分治总结
    有各种分治:CDQ分治,树上分治,数据结构上分治,根号分治,etc.普通分治求逆序对用归并排序求逆序对。Sol:其实逆序对是在归并排序时顺带求的,主要是归并排序。我们要对区间\([l,r]\)从小到大排序,先对\([l,mid],[mid+1,r]\)排序(这一步体现分治思想)。现在考虑怎么把两边合并。我们定义......
  • 一文详解“分治—归并“在算法中的应用
    找往期文章包括但不限于本期文章中不懂的知识点:个人主页:我要学编程(ಥ_ಥ)-CSDN博客所属专栏: 优选算法专题这里的归并与我们在数据结构中学习的归并排序是一样的,我们可以先来复习一下归并排序。用一道题来帮助我们回想起归并排序的细节。目录912.排序数组LCR170.交易......
  • 点分治学习笔记
    定义点分治,顾名思义,就是通过基于点的分治的一种算法。通常用于处理树上问题,如树上所有路径统计。我们设一次操作的时间复杂度为\(O(1)\),那么一次点分治复杂度为\(O(n\logn)\)。具体流程操作->分治->操作……(不知道怎么讲)点分治的核心主要在于高效的分治,每一次都可以将......
  • CDQ分治
    CDQ分治,解决三维数点(三维偏序)问题。第一维用分治化掉,用第一维<=mid的向第一维>mid的贡献,剩下的两维用二维数点解决。模板在线二维数点转化为离线三位数点其实任何在线k维数点都可以转化为离线(k+1)维数点,常见是把时间变成一维,每次数时间这一维比自己小且满足另两位限制的点(例1,......
  • cdq 分治
    简介cdq分治常用于计算序列中需要满足某些限制的点对对答案的贡献,通常点对有\(O(n^2)\)个。核心思想与普通分治类似,把点对分成前半个区间和后半个区间的点对,但cdq分治还要处理跨越区间中点的点对,这就是cdq分治的核心所在。算法流程下面以三维偏序为例。P3810【模板......