[51nod1766]树上的最远点对

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

 1 #include
 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){
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\n",z);
86     }
87 }
View Code

 

你可能感兴趣的:([51nod1766]树上的最远点对)