51nod 1766 树上的最远点对
Posted 1 2 f s_____
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51nod 1766 树上的最远点对相关的知识,希望对你有一定的参考价值。
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; }
以上是关于51nod 1766 树上的最远点对的主要内容,如果未能解决你的问题,请参考以下文章