zoukankan      html  css  js  c++  java
  • POJ 1741.Tree and 洛谷 P4178 Tree-树分治(点分治,容斥版) +二分 模板题-区间点对最短距离<=K的点对数量

    POJ 1741.
    Time Limit: 1000MS   Memory Limit: 30000K
    Total Submissions: 34141   Accepted: 11420

    Description

    Give a tree with n vertices,each edge has a length(positive integer less than 1001). 
    Define dist(u,v)=The min distance between node u and v. 
    Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k. 
    Write a program that will count how many pairs which are valid for a given tree. 

    Input

    The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l. 
    The last test case is followed by two zeros. 

    Output

    For each test case output the answer on a single line.

    Sample Input

    5 4
    1 2 3
    1 3 1
    1 4 2
    3 5 1
    0 0
    

    Sample Output

    8

    题意就是给你一个带边权的树,求树上最短距离<=K的点对数量。树分治模板题。

    代码:

      1 //树分治-点分治
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<cstring>
      6 #include<algorithm>
      7 #include<cmath>
      8 using namespace std;
      9 typedef long long ll;
     10 const int inf=1e9+10;
     11 const int maxn=1e5+10;
     12 
     13 int head[maxn],tot;
     14 int root,allnode,ans,n,k;
     15 int vis[maxn],deep[maxn],dis[maxn],siz[maxn],point[maxn];//deep[0]子节点个数(路径长度),point为重心节点
     16 
     17 struct node{
     18     int to,next,val;
     19 }edge[maxn<<1];
     20 
     21 void add(int u,int v,int w)//前向星存图
     22 {
     23     edge[tot].to=v;
     24     edge[tot].next=head[u];
     25     edge[tot].val=w;
     26     head[u]=tot++;
     27 }
     28 
     29 void init()//初始化
     30 {
     31     memset(head,-1,sizeof head);
     32     memset(vis,0,sizeof vis);
     33     tot=0;
     34 }
     35 
     36 void get_root(int u,int father)//重心
     37 {
     38     siz[u]=1;point[u]=0;
     39     for(int i=head[u];~i;i=edge[i].next){
     40         int v=edge[i].to;
     41         if(v==father||vis[v]) continue;
     42         get_root(v,u);//递归得到子树大小
     43         siz[u]+=siz[v];
     44         point[u]=max(point[u],siz[v]);//更新u节点的point
     45     }
     46     point[u]=max(point[u],allnode-siz[u]);//保存节点size
     47     if(point[u]<point[root]) root=u;//更新当前子树的重心
     48 }
     49 
     50 void get_dis(int u,int father)//获取子树所有节点与根的距离
     51 {
     52     deep[++deep[0]]=dis[u];
     53     for(int i=head[u];~i;i=edge[i].next){
     54         int v=edge[i].to;
     55         if(v==father||vis[v]) continue;
     56         int w=edge[i].val;
     57         dis[v]=dis[u]+w;
     58         get_dis(v,u);
     59     }
     60 }
     61 
     62 int cal(int u,int now)
     63 {
     64     dis[u]=now;deep[0]=0;
     65     get_dis(u,0);
     66     sort(deep+1,deep+deep[0]+1);
     67     int all=0;
     68     for(int l=1,r=deep[0];l<r;){//二分
     69         if(deep[l]+deep[r]<=k){
     70             all+=r-l;l++;
     71         }
     72         else r--;
     73     }
     74     return all;
     75 }
     76 
     77 void solve(int u)//以u为重心进行计算
     78 {
     79     ans+=cal(u,0);//以当前u为重心的贡献
     80     vis[u]=1;
     81     for(int i=head[u];~i;i=edge[i].next){
     82         int v=edge[i].to;
     83         if(vis[v]) continue;
     84         ans-=cal(v,edge[i].val);//减去子树的影响
     85         allnode=siz[v];
     86         root=0;
     87         get_root(v,u);
     88         solve(root);
     89     }
     90 }
     91 
     92 int main()
     93 {
     94     while(~scanf("%d%d",&n,&k)&&n&&k){
     95         init();
     96         for(int i=1;i<n;i++){
     97             int u,v,w;
     98             scanf("%d%d%d",&u,&v,&w);
     99             add(u,v,w);
    100             add(v,u,w);
    101         }
    102         root=ans=0;
    103         allnode=n;point[0]=inf;
    104         get_root(1,0);
    105         solve(root);
    106         printf("%d
    ",ans);
    107     }
    108     return 0;
    109 }

    洛谷  P4178 Tree

    一样的东西,就只是改了一下数据范围和输入格式。

    代码:

      1 //树分治-点分治
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<cstring>
      6 #include<algorithm>
      7 #include<cmath>
      8 using namespace std;
      9 typedef long long ll;
     10 const int inf=1e9+10;
     11 const int maxn=4e4+10;
     12 
     13 int head[maxn],tot;
     14 int root,allnode,ans,n,k;
     15 int vis[maxn],deep[maxn],dis[maxn],siz[maxn],point[maxn];//deep[0]子节点个数(路径长度),point为重心节点
     16 
     17 struct node{
     18     int to,next,val;
     19 }edge[maxn<<1];
     20 
     21 void add(int u,int v,int w)//前向星存图
     22 {
     23     edge[tot].to=v;
     24     edge[tot].next=head[u];
     25     edge[tot].val=w;
     26     head[u]=tot++;
     27 }
     28 
     29 void init()//初始化
     30 {
     31     memset(head,-1,sizeof head);
     32     memset(vis,0,sizeof vis);
     33     tot=0;
     34 }
     35 
     36 void get_root(int u,int father)//重心
     37 {
     38     siz[u]=1;point[u]=0;
     39     for(int i=head[u];~i;i=edge[i].next){
     40         int v=edge[i].to;
     41         if(v==father||vis[v]) continue;
     42         get_root(v,u);//递归得到子树大小
     43         siz[u]+=siz[v];
     44         point[u]=max(point[u],siz[v]);//更新u节点的point
     45     }
     46     point[u]=max(point[u],allnode-siz[u]);//保存节点size
     47     if(point[u]<point[root]) root=u;//更新当前子树的重心
     48 }
     49 
     50 void get_dis(int u,int father)//获取子树所有节点与根的距离
     51 {
     52     deep[++deep[0]]=dis[u];
     53     for(int i=head[u];~i;i=edge[i].next){
     54         int v=edge[i].to;
     55         if(v==father||vis[v]) continue;
     56         int w=edge[i].val;
     57         dis[v]=dis[u]+w;
     58         get_dis(v,u);
     59     }
     60 }
     61 
     62 int cal(int u,int now)
     63 {
     64     dis[u]=now;deep[0]=0;
     65     get_dis(u,0);
     66     sort(deep+1,deep+deep[0]+1);
     67     int all=0;
     68     for(int l=1,r=deep[0];l<r;){//二分
     69         if(deep[l]+deep[r]<=k){
     70             all+=r-l;l++;
     71         }
     72         else r--;
     73     }
     74     return all;
     75 }
     76 
     77 void solve(int u)//以u为重心进行计算
     78 {
     79     ans+=cal(u,0);//以当前u为重心的贡献
     80     vis[u]=1;
     81     for(int i=head[u];~i;i=edge[i].next){
     82         int v=edge[i].to;
     83         if(vis[v]) continue;
     84         ans-=cal(v,edge[i].val);//减去子树的影响
     85         allnode=siz[v];
     86         root=0;
     87         get_root(v,u);
     88         solve(root);
     89     }
     90 }
     91 
     92 int main()
     93 {
     94     scanf("%d",&n);
     95     init();
     96     for(int i=1;i<n;i++){
     97         int u,v,w;
     98         scanf("%d%d%d",&u,&v,&w);
     99         add(u,v,w);
    100         add(v,u,w);
    101     }
    102     scanf("%d",&k);
    103     root=ans=0;
    104     allnode=n;point[0]=inf;
    105     get_root(1,0);
    106     solve(root);
    107     printf("%d
    ",ans);
    108     return 0;
    109 }
  • 相关阅读:
    最近看到C#里面的抽象类和接口,还有索引器。
    Memcached服务端自动启动
    python操作MySQL数据库
    Linux开放端口
    关于数组的几道面试题
    这群超酷的开发者,是如何轻松搞定软件开发?
    五分钟开发好你的第一个人工智能应用
    Case Study: 技术和商业的结合点在哪里?
    【江湖趣事】话说开源界和微软的那些往日恩怨
    评微软收购GitHub
  • 原文地址:https://www.cnblogs.com/ZERO-/p/11283209.html
Copyright © 2011-2022 走看看