zoukankan      html  css  js  c++  java
  • [poj1741]Tree(点分治+容斥原理)

    题意:求树中点对距离<=k的无序点对个数。

    解题关键:树上点分治,这个分治并没有传统分治的合并过程,只是分成各个小问题,并将各个小问题的答案相加即可,也就是每层的复杂度并不在合并的过程,是在每层的处理过程。

    此题维护的是树上路径,考虑点分治。

    点分治的模板题,首先设点x到当前子树跟root的距离为,则满足${d_x} + {d_y} le k$可以加进答案,但是注意如果x,y在同一棵子树中,就要删去对答案的贡献,因为x,y会在其所在的子树中在计算一次。同一棵子树中不必考虑是否在其同一棵子树中的问题,因为无论是否在他的同一棵子树,都会对他的父节点产生影响。而这些影响都是无意义的。

    注意无根树转有根树的过程,需要选取树的重心防止复杂度从$O(n{log ^2}n)$退化为$O({n^2})$

    复杂度:$O(n{log ^2}n)$

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<cstdlib>
      5 #include<iostream>
      6 #include<cmath>
      7 #define inf 0x3f3f3f3f
      8 #define maxn 10004
      9 using namespace std;
     10 typedef long long ll;
     11 int head[maxn],cnt,n,k,ans,size,s[maxn],f[maxn],root,depth[maxn],num;//vis代表整体的访问情况,每个dfs不应该只用vis来存储
     12 bool vis[maxn];
     13 struct edge{
     14     int to,w,nxt;
     15 }e[maxn<<1];
     16 void add_edge(int u,int v,int w){
     17     e[cnt].to=v;
     18     e[cnt].w=w;
     19     e[cnt].nxt=head[u];
     20     head[u]=cnt++;
     21 }
     22 
     23 inline int read(){
     24     char k=0;char ls;ls=getchar();for(;ls<'0'||ls>'9';k=ls,ls=getchar());
     25     int x=0;for(;ls>='0'&&ls<='9';ls=getchar())x=(x<<3)+(x<<1)+ls-'0';
     26     if(k=='-')x=0-x;return x;
     27 }
     28 
     29 void get_root(int u,int fa){//get_root会用到size
     30     s[u]=1;f[u]=0;//f是dp数组
     31     for(int i=head[u];i!=-1;i=e[i].nxt){
     32         int v=e[i].to;
     33         if(v==fa||vis[v]) continue;
     34         get_root(v,u);
     35         s[u]+=s[v];
     36         f[u]=max(f[u],s[v]);
     37     }
     38     f[u]=max(f[u],size-s[u]);
     39     root=f[root]>f[u]?u:root;
     40 }
     41 
     42 void get_depth_size(int u,int fa,int dis){//同时获取size和depth
     43     depth[num++]=dis;
     44     s[u]=1;
     45     for(int i=head[u];i!=-1;i=e[i].nxt){
     46         int v=e[i].to;
     47         if(v==fa||vis[v]) continue;
     48         get_depth_size(v,u,dis+e[i].w);
     49         s[u]+=s[v];
     50     }
     51 }
     52 
     53 int calc(int u,int fa,int w){
     54     num=0;
     55     get_depth_size(u,fa,w);
     56     sort(depth,depth+num);
     57     int ret=0;
     58     for(int l=0,r=num-1;l<r;){
     59         if(depth[l]+depth[r]<=k) ret+=r-l++;
     60         else r--;
     61     }
     62     return ret;
     63 }
     64 
     65 void work(int u){
     66     vis[u]=true;
     67     ans+=calc(u,-1,0);
     68     for(int i=head[u];i!=-1;i=e[i].nxt){
     69         int v=e[i].to;
     70         if(vis[v]) continue;
     71         ans-=calc(v,u,e[i].w);
     72         size=s[v],root=0;
     73         get_root(v,u);
     74         work(root);
     75     }
     76 }
     77 
     78 void init(){
     79     memset(vis,false, sizeof vis);
     80     memset(head,-1,sizeof head);
     81     ans=cnt=0;
     82 }
     83 
     84 
     85 int main(){
     86     int a,b,c;
     87     f[0]=inf;
     88     while(scanf("%d%d",&n,&k)&&(n||k)){
     89         init();
     90         for(int i=0;i<n-1;i++){
     91             a=read(),b=read(),c=read();
     92             add_edge(a,b,c);
     93             add_edge(b,a,c);
     94         }
     95         size=n,root=0;
     96         get_root(1,-1);
     97         work(root);
     98         printf("%d
    ",ans);
     99     }
    100     return 0;
    101     
    102 }
  • 相关阅读:
    如何判断栈的增长方向
    时间复杂度
    shell基础part3
    shell基础part2
    shell基础part2
    linux基础part5
    linux基础part4
    linux基础part3
    linux基础part2
    shell基础part1
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/7486115.html
Copyright © 2011-2022 走看看