• BZOJ 3251 树上三角形:LCA【构成三角形的结论】


    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3251

    题意:

      给你一棵树,n个节点,每个点的权值为w[i]。

      接下来有m个形如(p,a,b)的操作:

        (1)p == 0:

          问你在从a到b的路径上,有没有三个点满足:它们的权值大小可以构成三角形。

          如果有,输出'Y',否则输出'N'。

        (2)p == 1:

          将点a的权值w[a]改为b。

    题解:

      首先考虑一个结论:

        因为构成三角形的充要条件是:对于三个数a < b < c,满足a + b > c。

        所以不能构成三角形的条件是:对于三个数a < b < c,满足a + b <= c。

        所以对于一个升序数列a[i],让a[i]的增加速度最小,则类似于斐波那契数列:1,1,2,3,5,8,13...

        又因为点权范围为[1,2^31-1],所以一个不能构成三角形的数列,最多有大约45个数字。

        即:对于数字个数 >= 50的数列,必定有三个数能构成三角形。

      

      所以先找出(a,b)的最近公共祖先act,然后顺着路径最多取50个数。

      然后sort一遍取出的数t[i],扫一遍有没有t[i-2]+t[i-1]>t[i]。

    AC Code:

      1 #include <iostream>
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include <algorithm>
      5 #include <vector>
      6 #define MAX_N 100005
      7 #define MAX_K 20
      8 
      9 using namespace std;
     10 
     11 int n,m;
     12 int w[MAX_N];
     13 int t[MAX_N];
     14 int dep[MAX_N];
     15 int par[MAX_K][MAX_N];
     16 vector<int> edge[MAX_N];
     17 
     18 void read()
     19 {
     20     scanf("%d%d",&n,&m);
     21     for(int i=1;i<=n;i++)
     22     {
     23         scanf("%d",&w[i]);
     24     }
     25     int a,b;
     26     for(int i=0;i<n-1;i++)
     27     {
     28         scanf("%d%d",&a,&b);
     29         edge[a].push_back(b);
     30     }
     31 }
     32 
     33 void dfs(int now,int p,int d)
     34 {
     35     dep[now]=d;
     36     par[0][now]=p;
     37     for(int i=0;i<edge[now].size();i++)
     38     {
     39         int temp=edge[now][i];
     40         if(temp!=p) dfs(temp,now,d+1);
     41     }
     42 }
     43 
     44 void init_lca(int root)
     45 {
     46     dfs(root,-1,0);
     47     for(int k=0;k+1<MAX_K;k++)
     48     {
     49         for(int i=1;i<=n;i++)
     50         {
     51             if(par[k][i]==-1) par[k+1][i]=-1;
     52             else par[k+1][i]=par[k][par[k][i]];
     53         }
     54     }
     55 }
     56 
     57 int lca(int a,int b)
     58 {
     59     if(dep[a]>dep[b]) swap(a,b);
     60     for(int k=0;k<MAX_N && dep[a]!=dep[b];k++)
     61     {
     62         if(((dep[b]-dep[a])>>k)&1)
     63         {
     64             b=par[k][b];
     65         }
     66     }
     67     if(a==b) return a;
     68     for(int k=MAX_K-1;k>=0;k--)
     69     {
     70         if(par[k][a]!=par[k][b])
     71         {
     72             a=par[k][a];
     73             b=par[k][b];
     74         }
     75     }
     76     return par[0][a];
     77 }
     78 
     79 bool check(int a,int b,int act)
     80 {
     81     int cnt=0;
     82     t[cnt++]=w[act];
     83     int now=a;
     84     while(now!=act)
     85     {
     86         t[cnt++]=w[now];
     87         now=par[0][now];
     88         if(cnt>50) break;
     89     }
     90     now=b;
     91     while(now!=act)
     92     {
     93         t[cnt++]=w[now];
     94         now=par[0][now];
     95         if(cnt>50) break;
     96     }
     97     sort(t,t+cnt);
     98     for(int i=2;i<cnt;i++)
     99     {
    100         if((long long)t[i-2]+t[i-1]>t[i]) return true;
    101     }
    102     return false;
    103 }
    104 
    105 void work()
    106 {
    107     init_lca(1);
    108     int p,a,b;
    109     for(int i=0;i<m;i++)
    110     {
    111         scanf("%d%d%d",&p,&a,&b);
    112         if(p==0)
    113         {
    114             int act=lca(a,b);
    115             if(check(a,b,act)) printf("Y
    ");
    116             else printf("N
    ");
    117         }
    118         else w[a]=b;
    119     }
    120 }
    121 
    122 int main()
    123 {
    124     read();
    125     work();
    126 }
  • 相关阅读:
    docker 学习
    Postman通过登录接口返回的token,然后请求其他接口时在header头中带上token信息
    c语言字符串常量赋值(多个双引号字符串常量组合成一个字符串常量)
    KEA之FTM、PWM
    SQL SERVER LEFT JOIN
    SQL SERVEL 合并表之间列
    C#时间操作帮助
    docker 安装 mysql
    python pip配置国内镜像
    python安装tensorflow
  • 原文地址:https://www.cnblogs.com/Leohh/p/7647701.html
Copyright © 2020-2023  润新知