1. 程式人生 > >51nod 1766 樹上的最遠點對(線段樹)

51nod 1766 樹上的最遠點對(線段樹)

最長路 char esp swa lin shu wap pen lib

  像樹的直徑一樣,兩個集合的最長路也是由兩個集合內部的最長路的兩個端點組成的,於是我們知道了兩個集合的最長路,枚舉一下兩兩端點算出答案就可以合並了,所以就可以用線段樹維護一個區間裏的最長路了。

技術分享
#include<iostream> 
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath> 
#include<algorithm> 
#define ll long long
using namespace std;
const int maxn=500010,inf=1e9; struct tjm{int too,dis,pre;}e[maxn]; struct poi{int p[3];ll dis;}tree[maxn<<2]; int n,m,a,b,x,y,z,tot; int d[maxn],son[maxn],size[maxn],fa[maxn],top[maxn],last[maxn]; ll dep[maxn]; inline void read(int &k) { int f=1;k=0;char c=getchar(); while(c<
0||c>9)c==-&&(f=-1),c=getchar(); while(c<=9&&c>=0)k=k*10+c-0,c=getchar(); k*=f; } void add(int x,int y,int z){e[++tot].too=y;e[tot].dis=z;e[tot].pre=last[x];last[x]=tot;} void dfs1(int x) { size[x]=1;d[x]=d[fa[x]]+1; for(int i=last[x],too=e[i].too;i;i=e[i].pre,too=e[i].too)
if(too!=fa[x]) { dep[too]=dep[x]+e[i].dis; fa[too]=x;dfs1(too); size[x]+=size[too]; if(size[too]>size[son[x]])son[x]=too; } } void dfs2(int x,int tp) { top[x]=tp; if(son[x])dfs2(son[x],tp); for(int i=last[x],too=e[i].too;i;i=e[i].pre,too=e[i].too) if(too!=fa[x]&&too!=son[x])dfs2(too,too); } int lca(int x,int y) { int f1=top[x],f2=top[y]; while(f1!=f2) { if(d[f1]<d[f2])swap(x,y),swap(f1,f2); x=fa[f1];f1=top[x]; } if(d[x]<d[y])swap(x,y); return y; } void pushup(poi x,poi y,ll &dist,int &p1,int &p2) { if(x.dis>y.dis)dist=x.dis,p1=x.p[1],p2=x.p[2]; else dist=y.dis,p1=y.p[1],p2=y.p[2]; for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) if(x.p[i]&&y.p[j]) { ll dis=dep[x.p[i]]+dep[y.p[j]]-(dep[lca(x.p[i],y.p[j])]<<1); if(dis>dist)dist=dis,p1=x.p[i],p2=y.p[j]; } } void build(int x,int l,int r) { if(l==r){tree[x].p[1]=tree[x].p[2]=l;return;} int mid=(l+r)>>1; build(x<<1,l,mid);build(x<<1|1,mid+1,r); pushup(tree[x<<1],tree[x<<1|1],tree[x].dis,tree[x].p[1],tree[x].p[2]); } void query(int x,int l,int r,int cl,int cr,ll &dis,int &p1,int &p2) { if(cl<=l&&r<=cr){dis=tree[x].dis;p1=tree[x].p[1];p2=tree[x].p[2];return;} int mid=(l+r)>>1; poi t1,t2;t1.dis=t2.dis=-1;t1.p[1]=t1.p[2]=t2.p[1]=t2.p[2]=0; if(cl<=mid)query(x<<1,l,mid,cl,cr,t1.dis,t1.p[1],t1.p[2]); if(cr>mid)query(x<<1|1,mid+1,r,cl,cr,t2.dis,t2.p[1],t2.p[2]); pushup(t1,t2,dis,p1,p2); } int main() { read(n); for(int i=1;i<n;i++)read(x),read(y),read(z),add(x,y,z),add(y,x,z); dfs1(1);dfs2(1,1); build(1,1,n); read(m); for(int i=1;i<=m;i++) { read(a),read(b),read(x),read(y); poi t1,t2;t1.dis=t2.dis=t1.p[1]=t1.p[2]=t2.p[1]=t2.p[2]=0;ll dis;int p1,p2; query(1,1,n,a,b,dis,t1.p[1],t1.p[2]);query(1,1,n,x,y,dis,t2.p[1],t2.p[2]); pushup(t1,t2,dis,p1,p2); printf("%lld\n",dis); } }
View Code

51nod 1766 樹上的最遠點對(線段樹)