zoukankan      html  css  js  c++  java
  • [51nod1766]树上的最远点对

    有一个结论:两个区间的最长路的端点一定是这两个区间中的最长路端点(4选2),所以可以用线段树来维护区间最长路的两个端点,然后最终合并即可

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 100005
     4 #define L (k<<1)
     5 #define R (L+1)
     6 #define mid (l+r>>1)
     7 struct ji{
     8     int nex,to,len;
     9 }edge[N<<1];
    10 struct zj{
    11     int a[2];
    12 }tr[N<<2];
    13 int E,n,m,x1,y11,x2,y2,x,y,z,head[N],in[N],out[N],sh[N],f[N][21];
    14 void add(int x,int y,int z){
    15     edge[E].nex=head[x];
    16     edge[E].to=y;
    17     edge[E].len=z;
    18     head[x]=E++;
    19 }
    20 bool pd(int x,int y){
    21     return (in[x]<=in[y])&&(out[y]<=out[x]);
    22 }
    23 int lca(int x,int y){
    24     if (pd(x,y))return x;
    25     for(int i=20;i>=0;i--)
    26         if (!pd(f[x][i],y))x=f[x][i];
    27     return f[x][0];
    28 }
    29 int dis(int x,int y){
    30     if ((!x)&&(!y))return -1;
    31     if ((!x)||(!y))return 0;
    32     return sh[x]+sh[y]-2*sh[lca(x,y)];
    33 }
    34 void dfs(int k,int fa,int s){
    35     sh[k]=s;
    36     in[k]=++x;
    37     f[k][0]=fa;
    38     for(int i=1;i<=20;i++)f[k][i]=f[f[k][i-1]][i-1];
    39     for(int i=head[k];i!=-1;i=edge[i].nex)
    40         if (edge[i].to!=fa)dfs(edge[i].to,k,s+edge[i].len);
    41     out[k]=++x;
    42 }
    43 zj merge(zj x,zj y){
    44     int ans=max(dis(x.a[0],x.a[1]),dis(y.a[0],y.a[1]));
    45     for(int i=0;i<2;i++)
    46         for(int j=0;j<2;j++)ans=max(ans,dis(x.a[i],y.a[j]));
    47     if (dis(x.a[0],x.a[1])==ans)return x;
    48     if (dis(y.a[0],y.a[1])==ans)return y;
    49     for(int i=0;i<2;i++)
    50         for(int j=0;j<2;j++)
    51             if (dis(x.a[i],y.a[j])==ans)return zj{x.a[i],y.a[j]};
    52 }
    53 void build(int k,int l,int r){
    54     if (l==r){
    55         tr[k]=zj{l,0};
    56         return;
    57     }
    58     build(L,l,mid);
    59     build(R,mid+1,r);
    60     tr[k]=merge(tr[L],tr[R]);
    61 }
    62 zj query(int k,int l,int r,int x,int y){
    63     if ((l>y)||(x>r))return zj{0,0};
    64     if ((x<=l)&&(r<=y))return tr[k];
    65     return merge(query(L,l,mid,x,y),query(R,mid+1,r,x,y));
    66 }
    67 int main(){
    68     scanf("%d",&n);
    69     memset(head,-1,sizeof(head));
    70     for(int i=1;i<n;i++){
    71         scanf("%d%d%d",&x,&y,&z);
    72         add(x,y,z);
    73         add(y,x,z);
    74     }
    75     x=0;
    76     dfs(1,1,0);
    77     build(1,1,n);
    78     scanf("%d",&m);
    79     for(int i=1;i<=m;i++){
    80         scanf("%d%d%d%d",&x1,&y11,&x2,&y2);
    81         z=0;
    82         zj o1=query(1,1,n,x1,y11),o2=query(1,1,n,x2,y2);
    83         for(int x=0;x<2;x++)
    84             for(int y=0;y<2;y++)z=max(z,dis(o1.a[x],o2.a[y]));
    85         printf("%d
    ",z);
    86     }
    87 }
    View Code
  • 相关阅读:
    利用杨辉三角和阶乘计算组合数
    验证字符串是否为回文数
    利用线性同余产生伪随机数+可变参数使用
    根据RandomStr.java:使用类型转换生成六位验证字符串。
    Java语言基础问题
    从命令行输入参数值,输出求和值。
    愚公移山_节选(伪代码)
    CodeForces
    CodeForces
    E
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/11629254.html
Copyright © 2011-2022 走看看