zoukankan      html  css  js  c++  java
  • [模板]点分治

    用途

    大规模地处理树上路径

    做法

    先考虑对x为根的子树做dfs来处理x子树到x的路径,然后统计答案,然后再递归地做x的儿子...

    然而当树退化成链时,最差复杂度是$O(n^2)$的

    类比一维中二分的做法,其实是使左右区间尽量平均,那我们也让我们要处理的点的子树大小尽量平均

    具体来说,我们每次想要做x这个子树的时候,会想先在这个子树中找到一个点root,使得它的每个子树大小的最大值最小,然后将root作为这棵子树的新根,再继续处理路径

    我们通过dfs来统计子树的大小以选定root,需要注意的是,由于某个点的父亲将来也有可能变成它的孩子(如果它被选为根的话),那就也需要算父亲作为它的孩子时的大小,其实就是S-size[x],其中S是这棵树的总大小

    这样复杂度就是$O(nlogn)$的了

    然而还有一个很重要的问题:我在以x为根去dfs找路径的时候,可能会找到两个端点在同一个子树的情况,这显然是不合法的。我们可以有两种方法来处理这种情况

    1.(适用于大多数情况)在处理x的子树y的时候,先钦定住要走x到y这条边,也同样计算一波路径,这样算出来的就一定是刚才的不合法情况,减掉就完事了

    2.(适用于可以单独地对于某条路径O(1)地统计答案)我不做x,而是对x的每个儿子y,先用子树y统计答案,再用子树y更新答案,为以后的统计铺路,这样做,我统计到的答案一定不在同一个子树里,也就不会出现上面的问题。(例:bzoj2599 Race

    例题:

    luogu4178 求距离不超过K的路径数

     1 #include<bits/stdc++.h>
     2 #define pa pair<int,int>
     3 #define ll long long
     4 using namespace std;
     5 const int maxn=40040;
     6 
     7 inline ll rd(){
     8     ll x=0;char c=getchar();int neg=1;
     9     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
    10     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    11     return x*neg;
    12 }
    13 
    14 struct Edge{
    15     int a,b,l,ne;
    16 }eg[maxn*2];
    17 int egh[maxn],ect;
    18 int N,K;
    19 int mins,smsiz,pct;
    20 int siz[maxn],dis[maxn],ans,fa[maxn];
    21 bool flag[maxn];
    22 
    23 inline void adeg(int a,int b,int l){
    24     eg[++ect].a=a;eg[ect].b=b;eg[ect].l=l;
    25     eg[ect].ne=egh[a];egh[a]=ect;
    26 }
    27 
    28 void getroot(int &rt,int x){
    29     int mm=0;siz[x]=1;
    30     for(int i=egh[x];i!=-1;i=eg[i].ne){
    31         int b=eg[i].b;if(b==fa[x]||flag[b]) continue;
    32         fa[b]=x;getroot(rt,b);
    33         siz[x]+=siz[b];mm=max(siz[b],mm);
    34     }mm=max(smsiz-siz[x],mm);
    35     if(mm<mins) mins=mm,rt=x;
    36 }
    37 
    38 void getdis(int x,int f,int d){
    39     dis[++pct]=d;
    40     for(int i=egh[x];i!=-1;i=eg[i].ne){
    41         int b=eg[i].b;if(b==f||flag[b]) continue;
    42         getdis(b,x,eg[i].l+d);
    43     }
    44 }
    45 
    46 int calc(int x,int tt){
    47     pct=0;getdis(x,0,tt);int re=0;
    48     sort(dis+1,dis+pct+1);
    49     int l=1,r=pct;
    50     while(l<r){
    51         if(dis[l]+dis[r]<=K) re+=r-l,l++;
    52         else r--;
    53     }return re;
    54 }
    55 
    56 void solve(int x){
    57     flag[x]=1;
    58     ans+=calc(x,0);
    59     for(int i=egh[x];i!=-1&&i;i=eg[i].ne){
    60         int b=eg[i].b;if(flag[b]) continue;
    61         ans-=calc(b,eg[i].l);
    62         mins=0x3f3f3f3f,smsiz=siz[b];
    63         int root=0;getroot(root,b);
    64         siz[fa[root]]=smsiz-siz[root];
    65         solve(root);
    66     }
    67 }
    68 
    69 int main(){
    70     int i,j,k;
    71     //freopen("4178.in","r",stdin);
    72     N=rd();memset(egh,-1,sizeof(egh));
    73     for(i=1;i<N;i++){
    74         int a=rd(),b=rd(),c=rd();
    75         adeg(a,b,c);adeg(b,a,c);
    76     }K=rd();
    77     smsiz=N;mins=0x3f3f3f3f;
    78     int root=0;getroot(root,1);
    79     solve(root);
    80     printf("%d
    ",ans);
    81 
    82     return 0;
    83 }
    luogu4178

    bzoj2599/luogu4149 求距离为K的路径的最小边数

     1 #include<bits/stdc++.h>
     2 #define pa pair<int,int>
     3 #define ll long long
     4 using namespace std;
     5 const int maxn=200020,maxk=1000010;
     6 
     7 inline ll rd(){
     8     ll x=0;char c=getchar();int neg=1;
     9     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
    10     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    11     return x*neg;
    12 }
    13 
    14 int N,K;
    15 struct Edge{
    16     int b,ne,l;
    17 }eg[maxn*2];
    18 int egh[maxn],ect;
    19 int siz[maxn],pct;
    20 bool flag[maxn];
    21 int root,ms,smsiz;
    22 int dis[maxk],ans=0x3f3f3f3f;
    23 queue<int> dq;
    24 
    25 
    26 inline void adeg(int a,int b,int l){
    27     eg[++ect].b=b;eg[ect].l=l;eg[ect].ne=egh[a];egh[a]=ect;
    28 }
    29 
    30 void getroot(int x,int f){
    31     siz[x]=1;int mm=0;
    32     for(int i=egh[x];i;i=eg[i].ne){
    33         int b=eg[i].b;if(flag[b]||b==f) continue;
    34         getroot(b,x);
    35         siz[x]+=siz[b];mm=max(siz[b],mm);
    36     }mm=max(smsiz-siz[x],mm);
    37     if(mm<ms) ms=mm,root=x;
    38 }
    39 
    40 void getdis(int x,int f,int d,int dep){
    41     if(d<=K){
    42         if(dis[d]>2e5) dq.push(d);
    43         dis[d]=min(dis[d],dep);
    44     }else return;
    45     for(int i=egh[x];i;i=eg[i].ne){
    46         int b=eg[i].b;if(flag[b]||b==f) continue;
    47         getdis(b,x,d+eg[i].l,dep+1);
    48     }
    49 }
    50 void calans(int x,int f,int d,int dep){
    51     if(d<=K){
    52         if(dis[K-d]<=2e5) ans=min(ans,dep+dis[K-d]);
    53     }else return;
    54     for(int i=egh[x];i;i=eg[i].ne){
    55         int b=eg[i].b;if(flag[b]||b==f) continue;
    56         calans(b,x,d+eg[i].l,dep+1);
    57     }
    58 }
    59 
    60 inline void solve(int x){
    61     flag[x]=1;
    62     for(int i=egh[x];i;i=eg[i].ne){
    63         int b=eg[i].b;if(flag[b]) continue;
    64         calans(b,x,eg[i].l,1);
    65         getdis(b,x,eg[i].l,1);
    66     }while(!dq.empty()) dis[dq.front()]=0x3f3f3f3f,dq.pop();
    67     int ss=smsiz;
    68     for(int i=egh[x];i;i=eg[i].ne){
    69         int b=eg[i].b;if(flag[b]) continue;
    70         ms=0x3f3f3f3f;smsiz=siz[b]>siz[x]?ss-siz[x]:siz[b];
    71         getroot(b,x);solve(root);
    72     }
    73 }
    74 
    75 int main(){
    76     int i,j,k;
    77     N=rd(),K=rd(); 
    78     for(i=1;i<N;i++){
    79         int a=rd()+1,b=rd()+1,c=rd();
    80         adeg(a,b,c);adeg(b,a,c);
    81     }memset(dis,127,sizeof(dis));dis[0]=0;
    82     smsiz=N;ms=0x3f3f3f3f;getroot(1,0);
    83     solve(root);
    84     if(ans<=2e5) printf("%d
    ",ans);
    85     else printf("-1
    ");
    86     return 0;
    87 }
    bzoj2599
  • 相关阅读:
    Fedora 14 安装完后的设置 添加源 更新软件
    visual studio NuGet 常用包管理命令
    ubuntu通过cifs-utils访问Windows共享目录
    C# 数据库写入Sql Bulk索引损坏异常问题System.InvalidOperationException: DataTable internal index is corrupted: '4'
    C# IEnumerable to List 的转换
    python 端口扫描
    ubuntu 关闭 phpmyadmin
    zendframework 初始化配置
    zend-form笔记
    DirectX 图形流水线
  • 原文地址:https://www.cnblogs.com/Ressed/p/9649159.html
Copyright © 2011-2022 走看看