• 点分治


    点分治:点分治,是处理树上路径的一个极好的工具。一般如果需要大规模处理树上路径,点分治是一个不错的选择。

    推荐大佬的一个视频:here

    可以看这个博客加以理解点分治:here,不过我的代码并不是用的这篇博客的

    模板题:P3806 【模板】点分治1

    题目描述

    给定一棵有 n 个点的树,询问树上距离为 k 的点对是否存在。

    输入格式

    第一行两个数 n,m.

    第 2 到第 n 行,每行三个整数 u, v, w,代表树上存在一条连接 u 和 v 边权为 w 的路径。

    接下来 m 行,每行一个整数 k,代表一次询问。

    输出格式

    对于每次询问输出一行一个字符串代表答案,存在输出 AYE,否则输出 NAY

    输入输出样例

    输入 #1
    2 1
    1 2 2
    2
    输出 #1
    AYE

    说明/提示

    数据规模与约定

    对于 30% 的数据,保证 n100。

    对于 60% 的数据,保证 n1000,m50 。

    对于 100% 的数据,保证 1n10^4,1m100,1k10^7,1u,vn,1w10^4。`

    AC_Code:模板

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 typedef long long ll;
      4 const int maxn = 1e5+10;
      5 const int maxm = 1e7+1000;
      6 const int inf = 0x3f3f3f3f;
      7 
      8 struct edge{
      9     int to,w,nxt;
     10 }e[maxn<<1];
     11 
     12 int _size,head[maxn],que[maxn],maxp[maxn],dis[maxn];
     13 int sz[maxn],ans[maxn],tot,rt;
     14 bool vis[maxm],judge[maxm];
     15 int tmp[maxm];
     16 int n,m;
     17 
     18 void addedge(int u,int v,int w){
     19     e[_size].to=v; e[_size].w=w; e[_size].nxt=head[u]; head[u]=_size++;
     20 }
     21 
     22 void dfs_zx(int u,int fa){
     23     sz[u]=1;
     24     maxp[u]=0;
     25     for(register int i=head[u];~i;i=e[i].nxt){
     26         int to = e[i].to;
     27         if( to==fa || vis[to] ) continue;
     28         dfs_zx(to,u);
     29         sz[u] += sz[to];
     30         maxp[u] = max(maxp[u],sz[to]);
     31     }
     32     maxp[u] = max(maxp[u], tot-sz[u]);
     33     if( maxp[u]<maxp[rt] ){
     34         rt = u;
     35     }
     36     return ;
     37 }
     38 
     39 void get_dis(int root,int fa){
     40     tmp[ ++tmp[0] ] = dis[root];
     41     for(int i=head[root];~i;i=e[i].nxt){
     42         int to=e[i].to, _dis=e[i].w;
     43         if( vis[to] || to==fa ) continue;
     44         dis[to] = dis[root] + _dis;
     45         get_dis(to, root);
     46     }
     47 }
     48 
     49 void calc(int rt){
     50     queue<int> q;
     51     for(int i=head[rt];~i;i=e[i].nxt){
     52         int to=e[i].to, _dis=e[i].w;
     53         if( vis[to] ) continue; //保证只往下搜
     54         tmp[0] = 0;             //tmp记录当前子树算出的距离,tmp[0]相当于设了一个cnt计数器
     55         dis[to] = _dis;         //dis[to]为rt与to之间的距离
     56         get_dis(to,rt);
     57         for(int j=tmp[0]; j; j--){      //枚举所有长度
     58             for(int k=1; k<=m; k++){    //枚举所有询问
     59                 if( que[k]>=tmp[j] ){   //如果询问大于单条路径长度,那就有可能存在
     60                     ans[k] |= judge[que[k]-tmp[j]];//如果能用两条路径拼出来,那就存在
     61                 }
     62             }
     63         }
     64 
     65         for(int j=tmp[0];j;j--){    //把存在的单条路径长度标上true,供下个子树用
     66             q.push(tmp[j]);
     67             judge[tmp[j]]=true;
     68         }
     69     }
     70 
     71     while(!q.empty())     //清空judge数组,不要用memset,会超时
     72     {
     73         judge[q.front()]=false;
     74         q.pop();
     75     }
     76 }
     77 
     78 void solve(int root){
     79     vis[root]=true; //标记访问过
     80     judge[0]=true;  //到当前根长度是0的肯定存在,标记true
     81     calc(root);     //计算经过根结点的路径
     82     for(int i=head[root];~i;i=e[i].nxt){
     83         int to=e[i].to;
     84         if( vis[to] ) continue;
     85         maxp[rt=0] =  tot = sz[to];
     86         dfs_zx(to,0);
     87         dfs_zx(rt,0);
     88         solve(rt);
     89     }
     90 }
     91 
     92 void init(){
     93     memset(head,-1,sizeof(head));
     94     _size=0;
     95 }
     96 
     97 int main()
     98 {
     99     init();
    100 
    101     cin>>n>>m;
    102     for(int i=1;i<n;i++){
    103         int u,v,w; cin>>u>>v>>w;
    104         addedge(u,v,w); addedge(v,u,w);
    105     }
    106     for(int i=1;i<=m;i++) cin>>que[i];
    107     maxp[rt=0] = n; //相当于设了一个maxx
    108     tot = n;        //记录当前树的大小
    109     dfs_zx(1,0);    //找重心   //此时siz数组存放的是以1为根时的各树大小,需要以找出的重心为根重算
    110     dfs_zx(rt,0);
    111     solve(rt);
    112     for(int i=1;i<=m;i++){
    113         if( ans[i] ) cout<<"AYE"<<endl;
    114         else cout<<"NAY"<<endl;
    115     }
    116     return 0;
    117 }
  • 相关阅读:
    Eugene and an array CodeForces
    Kind Anton CodeForces
    浙江大学PAT上机题解析之1011. World Cup Betting (20)
    九度OnlineJudge之1001:A+B for Matrices
    九度OnlineJudge之1468:Sharing
    九度OnlineJudge之1464:Hello World for U
    C++ STL 学习笔记
    浙江大学PAT上机题解析之1009. Product of Polynomials (25)
    浙江大学PAT上机题解析之1050. String Subtraction (20)
    浙江大学PAT上机题解析之1008. Elevator (20)
  • 原文地址:https://www.cnblogs.com/wsy107316/p/13765704.html
Copyright © 2020-2023  润新知