• [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 }
  • 相关阅读:
    1442. Count Triplets That Can Form Two Arrays of Equal XOR
    1441. Build an Array With Stack Operations
    312. Burst Balloons
    367. Valid Perfect Square
    307. Range Sum Query
    1232. Check If It Is a Straight Line
    993. Cousins in Binary Tree
    1436. Destination City
    476. Number Complement
    383. Ransom Note
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/7486115.html
Copyright © 2020-2023  润新知