zoukankan      html  css  js  c++  java
  • luogu P3806 【模板】点分治1

    题目描述

    给定一棵有n个点的树

    询问树上距离为k的点对是否存在。

    (多次询问&&可离线)

    我们先随意指定一个虚拟根root,将这棵树转化成无根树

    树上的路径可以分为两类,

    1.经过根节点u的路径

    2.完全在u子树里(不经过u)的

    对于1,用dis表示当前结点到根节点root的路径长度, 则root的子树中两个节点u到v的路径长即为dis[u]+dis[v]

    对于2,u到v的路径完全在root的某个子树内, 那么就找到这棵子树的根,对它再求一次第一种路径

    就是不断的寻找重心,把原来的树分成很多小的树,并对每个子树分别求解

    maxx[u]表示u的儿子的子树中,最大的大小

    则树的重心就是maxx值最小的那个节点

      1 #include<cstdio>
      2 #include<iostream>
      3 #define maxn 100010
      4 using namespace std;
      5 int n,m,text[maxn],t[maxn],root; 
      6 int sum,size[maxn],maxx[maxn];
      7 int head[maxn*3],nxt[maxn*3],to[maxn*3],val[maxn*3],cnt;
      8 int vis[maxn],vis1[maxn],vis2[maxn],dis[maxn],judge[10000010];
      9 void add(int a,int b,int v)
     10 {
     11     cnt++;
     12     nxt[cnt]=head[a];
     13     head[a]=cnt;
     14     to[cnt]=b;
     15     val[cnt]=v;
     16 }
     17 void getroot(int u,int fa)//找到以u为跟的子树的重心 
     18 {
     19     size[u]=1;
     20     for(int i=head[u];i;i=nxt[i])
     21     {
     22         if(to[i]==fa||vis[to[i]]) continue;
     23         getroot(to[i],u);
     24         size[u]+=size[to[i]];//u的子树的大小包括所有子树的大小的和加一 
     25         maxx[u]=max(maxx[u],size[to[i]]);
     26     }
     27     maxx[u]=max(maxx[u],sum-maxx[u]);//保存u把整棵树分成两部分后大的部分的大小 
     28     if(maxx[u]<maxx[root]) root=u;//重心几乎把树分成平均两部分 
     29     return;
     30 }
     31 void getdis(int u,int f)
     32 {
     33     vis2[++vis2[0]]=dis[u];   //保存root到根节点中每一个点的距离 
     34     for(int i=head[u];i;i=nxt[i])
     35     {
     36         if(vis[to[i]]||to[i]==f) continue;
     37         dis[to[i]]=dis[u]+val[i]; //dis[u]保存此时的root到u的距离 
     38         getdis(to[i],u);
     39     }
     40     return;
     41 }
     42 void qiu(int u)
     43 {
     44     vis1[0]=0;
     45     for(int i=head[u];i;i=nxt[i])
     46     {
     47         if(vis[to[i]]) continue;
     48         vis2[0]=0;
     49         dis[to[i]]=val[i];
     50         getdis(to[i],u);
     51         for(int j=1;j<=vis2[0];j++)
     52             for(int o=1;o<=m;o++)
     53                 if(text[o]>=vis2[j]&&t[o]==0) t[o]=judge[text[o]-vis2[j]];
     54                 //若u的子树中存在两条以u为节点的不同路径经长度和为 text[o],那么就存在长度为text[u]的路径 
     55         for(int j=1;j<=vis2[0];j++)
     56         {
     57             vis1[++vis1[0]]=vis2[j];
     58             judge[vis2[j]]=1;
     59             //保存存在的从root到u的子树的点的路径长度 
     60         } 
     61     }
     62     for(int i=1;i<=vis1[0];i++) judge[vis1[i]]=0;//下一次不经过u及其子树,删去因此存在的路径长度 
     63     return;
     64 } 
     65 void solve(int u) //进行点分治
     66 {
     67     vis[u]=1;
     68     judge[0]=1;//解决一条路径端点分别为root与某个子节点时,这条路径可以直接充当答案,相当于与一条长为0的路径进行了第一种情况,所以长度为0的路径永远存在
     69     qiu(u);
     70     for(int i=head[u];i;i=nxt[i])
     71     {
     72         if(vis[to[i]]) continue;
     73         sum=size[to[i]];
     74         root=0;
     75         maxx[0]=2e9;//最开始设一个虚拟的点为重心 
     76         getroot(to[i],0);
     77         solve(root);
     78     }
     79     return;
     80 }
     81 int main()
     82 {
     83     scanf("%d%d",&n,&m);
     84     for(int i=1;i<n;i++)
     85     {
     86         int a,b,c;
     87         scanf("%d%d%d",&a,&b,&c);
     88         add(a,b,c);
     89         add(b,a,c);
     90     }
     91     for(int i=1;i<=m;i++) 
     92         scanf("%d",&text[i]);  //离线计算 ,保存每个k 
     93     maxx[root]=n;
     94     sum=n;
     95     getroot(1,0);  //找到整颗树的重心 
     96     solve(root);   //由整颗树的重心开始点分治 
     97     for(int i=1;i<=m;i++)
     98     {
     99         if(t[i]) printf("AYE
    ");
    100         else printf("NAY
    ");
    101     }
    102     return 0;
    103 } 
  • 相关阅读:
    利用SVN合并代码(merge)
    Swagger UI初识
    Jenkins详细教程
    Hangfire 分布式后端作业调度框架服务
    【转】Centos下MySQL使用总结
    MySQL基础
    IDE:IDEA Commit Changes Dialog local changes refresh
    JavaEE:JavaEE技术组成
    MyBatis-Exception:org.apache.ibatis.exceptions.PersistenceException
    JSON-fastjson
  • 原文地址:https://www.cnblogs.com/QAQq/p/10396067.html
Copyright © 2011-2022 走看看