51nod 1766 树上的最远点对

Posted 1 2 f s_____

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51nod 1766 树上的最远点对相关的知识,希望对你有一定的参考价值。

基准时间限制:3 秒 空间限制:524288 KB
 
n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j<=d}
(PS 建议使用读入优化)
Input
第一行一个数字 n n<=100000。
第二行到第n行每行三个数字描述路的情况, x,y,z (1<=x,y<=n,1<=z<=10000)表示x和y之间有一条长度为z的路。
第n+1行一个数字m,表示询问次数 m<=100000。
接下来m行,每行四个数a,b,c,d。
Output
共m行,表示每次询问的最远距离
Input示例
5
1 2 1
2 3 2
1 4 3
4 5 4
1
2 3 4 5
Output示例
10
-----
解:线段树,ST表,lca

这题需要一个结论

设集合A中的最远点对为u,v

集合B中的最远点对为p,q

那么集合 A并B 的最远点对为u,v,p,q中的两个(即C(4,2)==6)

证明类似树的直径的证明

===

写到心态崩,重写了好几次;

rmq&lca 写了好几次,看不懂别人的,只自己用个结构体弄;

线段树的pushup函数崩了好多次,好像是因为p=l.u还是p=l.v的问题(但我不认为这样会有问题);

 

技术分享
#include<cstdio>
#include<cstring>
#include<algorithm>
using std::swap;
using std::min;
const int N=200017;
inline int read()  
{  
    int ans=0,f=1;char t=getchar();  
    while(t<0||t>9)   f=(t==-?-1:1),t=getchar();  
    while(t>=0&&t<=9) ans=ans*10+t-0,t=getchar();  
    return ans*f;  
}  
int dep[N],tar[N],dfn[N],book[N],dis[N],line[N];
struct node
{
    int from,to,next,p;
}e[N];
int first[N];
int cnt=0;
void insert(int u,int v,int p)
{
    e[++cnt].to=v;e[cnt].next=first[u];first[u]=cnt;e[cnt].p=p;
    e[++cnt].to=u;e[cnt].next=first[v];first[v]=cnt;e[cnt].p=p;
}
void dfs(int x)
{
    dfn[++cnt]=x,tar[x]=cnt,line[cnt]=dep[x];book[x]=1;
    for(int i=first[x];i;i=e[i].next)
    {        
        if(!book[e[i].to])
        {        
            dis[e[i].to]=dis[x]+e[i].p;    
            dep[e[i].to]=dep[x]+1;
            dfs(e[i].to);            
            line[++cnt]=dep[x];    
            dfn[cnt]=x;
        }
    }
}
struct flagg
{
    int dp,zi;
}f[N<<1][27];
int lg[N<<1];
inline int lca(int l,int r)  
{  
    l=tar[l],r=tar[r];  
    if(l>r)  swap(l,r); 
    int t=lg[r-l+1];  
    int x,y;
    x=f[l][t].dp,y=f[r-(1<<t)+1][t].dp;
    if(x<=y) return f[l][t].zi;    
    else     return f[r-(1<<t)+1][t].zi;
 //   if(line[a].depth<=line[b].depth) return line[a].zi;
  //  else return line[b].zi;
  //  printf("%%%%   %d\n",t);    
//    if(ans==f[l][t]) return dfn[l];
//    else return dfn[r-(1<<t)+1];
}  
struct edgt
{
    int l,r,v,u,dis;
}tr[N<<2];
#define ll ro<<1
#define rr ro<<1|1 
const int inf=1e9+12;
inline int getdis(int u,int v)
{
    return dis[u]+dis[v]-(dis[dfn[lca(u,v)]]<<1);
}
inline void pushup(edgt &ro,edgt l,edgt r,int flag)  
{  
    bool tag1=( (l.l==l.r) &&l.l>0),tag2=( (r.l==r.r) && (r.l>0) );  
    int ans=0,tt=0,i=0,j=0;
    if(tag1&&!tag2)  
    {          
        if(flag) if(r.dis>ans)    ans=r.dis,i=r.u,j=r.v;  
          
        tt=getdis(l.u,r.u);  
        if(tt>ans)   ans=tt,i=l.u,j=r.u;          
        tt=getdis(l.u,r.v);  
        if(tt>ans)   ans=tt,i=l.u,j=r.v;            
        ro.dis=ans,ro.u=i,ro.v=j;  
    }  
    else if(!tag1&&tag2)  
    {          
        if(flag) if(l.dis>ans)    ans=l.dis,i=l.u,j=l.v;  
          
        tt=getdis(l.u,r.u);  
        if(tt>ans)   ans=tt,i=l.u,j=r.u;            
        tt=getdis(l.v,r.u);  
        if(tt>ans)   ans=tt,i=l.v,j=r.u;  
        ro.dis=ans,ro.u=i,ro.v=j;  
    }  
    else if(tag1&&tag2)  
    {  
        ro.u=l.l;ro.v=r.l;  
        ro.dis=getdis(ro.u,ro.v);   
    }  
    else   
    {          
        if(flag) if(l.dis>ans)    ans=l.dis,i=l.u,j=l.v;  
        if(flag) if(r.dis>ans)    ans=r.dis,i=r.u,j=r.v;  
        
        tt=getdis(l.u,r.u);  
        if(tt>ans)   ans=tt,i=l.u,j=r.u;            
        tt=getdis(l.u,r.v);  
        if(tt>ans)   ans=tt,i=l.u,j=r.v;        
        tt=getdis(l.v,r.u);  
        if(tt>ans)   ans=tt,i=l.v,j=r.u;            
        tt=getdis(l.v,r.v);  
        if(tt>ans)   ans=tt,i=l.v,j=r.v;           
        ro.dis=ans,ro.u=i,ro.v=j;  
    }  
}  
void build(int ro,int l,int r)
{
    tr[ro].l=l,tr[ro].r=r;
    if(l==r)
    {
        tr[ro].v=tr[ro].u=l;
        tr[ro].dis=-inf;
        return;
    }
    int mid=(l+r)>>1;
    build(ll,l,mid);
    build(rr,mid+1,r);
    pushup(tr[ro],tr[ll],tr[rr],1);
}
edgt query(int ro,int l,int r)  
{  
    if(l<=tr[ro].l&&tr[ro].r<=r)      return tr[ro];  
    int mid=(tr[ro].l+tr[ro].r)>>1;  
    if(r<=mid)   return query(ll,l,r);  
    else if(l>mid)   return query(rr,l,r);  
    else  
    {  
        edgt ans;  
        edgt a=query(ll,l,mid),b=query(rr,mid+1,r);  
        pushup(ans,a,b,1);  
        return ans;  
    }  
}  
int main()
{
    int n;
    n=read();
    int v,u,p;
    for(int i=1;i<n;i++) v=read(),u=read(),p=read(),insert(v,u,p);
    dep[1]=1;
    cnt=0;
    dfs(1);
//    for(int i=1;i<=n;i++) printf("%d ",dis[i]);
//    for(int i=1;i<=n;i++) printf("%d ",dep[i]);
//    printf("*********\n");
//    for(int i=1;i<=cnt;i++)
//        printf("std:: i : %d line : %d tar : %d dfn : %d\n",i,line[i],tar[i],dfn[i]);
    //lca&rmq:
    lg[1]=0;  
    for(int i=2;i<=cnt;i++)      lg[i]=lg[i>>1]+1;   
    for(int i=1;i<=cnt;i++)  f[i][0].dp=line[i],f[i][0].zi=i;  
      
    int x,y;
    for(int j=1;j<=22;j++)  
    for(int i=1;i<=cnt-( 1<<(j -1) );i++)
    {
        x=f[i][j-1].dp,y=f[ i+( 1<< (j-1) )][ j-1 ].dp;
        if(x<=y) f[i][j].dp=x,f[i][j].zi=f[i][j-1].zi;        
        else     f[i][j].dp=y,f[i][j].zi=f[ i+( 1<< (j-1) )][ j-1 ].zi;
    }     
//    printf("std:: %d",lca(1,3));   
    //tree:
    build(1,1,n);
//    for(int i=1;i<=20;i++)
//        printf("tree:: %d %d %d %d %d\n",tr[i].l,tr[i].r,tr[i].v,tr[i].u,tr[i].dis);
//    printf("std:: %d \n",getdis(3,5)); 
       int m=read();
       int a,b,c,d;
       for(int i=1;i<=m;i++)
       {
          a=read(),b=read(),c=read(),d=read();
          edgt x=query(1,a,b),y=query(1,c,d),ans;
  //        printf("lca:: a,b: %d c,d: %d\n",dfn[lca(a,b)],dfn[lca(c,d)]);
       pushup(ans,x,y,0);
       printf("%d\n",ans.dis); 
       }
    return 0;
}
View Code

 

 

 





以上是关于51nod 1766 树上的最远点对的主要内容,如果未能解决你的问题,请参考以下文章

51nod1766 树上的最远点对

51 nod 1766 树上的最远点对(线段树+lca)

51nod 1766 树上的最远点对(线段树)

51nod 1766 树上的最远点对

做题51Nod1766树上的最远点对——直径&线段树

51Nod.1766.树上最远点对(树的直径 RMQ 线段树/ST表)