1787: [Ahoi2008]Meet 紧急集合
http://www.lydsy.com/JudgeOnline/problem.php?id=1787
RunID | User | Problem | Result | Memory | Time | Language | Code_Length | Submit_Time |
375404 | Liu_Ts | 1787 | Accepted | 45732 kb | 7584 ms | C++ | 2039 B | 2013-03-25 11:25:27 |
题意
一棵树,每次询问给三个点,求一个点使得到这三个点的距离和最小。
题解
理解一下,可知答案必定在这三个点中,某两个点的LCA上,
于是枚举a,b;a,c;b,c的LCA。
最后发现这三个LCA有规律,有两个一定相同,但是不会用。
LCA写的RMQ比较慢啊
#include<cstring> #include<climits> #include<cmath> #include<cstdio> #include<algorithm> using namespace std; const int N=500001,M=1000001,Q=2000002; int q[Q],d[N],tot,n,k,v[M],next[M],head[N],num[N],m; struct SegmentTree { int m[6000002]; void update(int x) { int l=x<<1,r=l+1; m[x]=m[l]; if(d[m[x]]>d[m[r]]) m[x]=m[r]; } void build(int x,int s,int t) { if(s==t) { m[x]=q[s];return; } int mid=s+t>>1; build(x<<1,s,mid);build((x<<1)+1,mid+1,t); update(x); } int get(int x,int s,int t,int ll,int rr) { if(ll<=s&&t<=rr) return m[x]; int t1=0,t2=0,mid=s+t>>1; if(ll<=mid) t1=get(x<<1,s,mid,ll,rr); if(rr>mid) t2=get((x<<1)+1,mid+1,t,ll,rr); if(d[t1]<d[t2]) return t1; else return t2; } }a; void add(int x,int y) { v[++k]=y;next[k]=head[x];head[x]=k; } void dfs(int x,int fa,int deep) { q[++q[0]]=x;num[x]=q[0];d[x]=deep; for(int i=head[x];i;i=next[i]) if(v[i]!=fa) dfs(v[i],x,deep+1),q[++q[0]]=x; } int lca(int x,int y) { if(num[x]>num[y]) swap(x,y); return a.get(1,1,q[0],num[x],num[y]); } int main() { scanf("%d%d",&n,&m);int x,y,z; for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y);add(y,x); } dfs(1,0,0);d[0]=INT_MAX; a.build(1,1,q[0]); int p,q; while(m--) { int ans,sum=INT_MAX; scanf("%d%d%d",&x,&y,&z); int s=d[x]+d[y]+d[z]; p=lca(x,y);q=lca(p,z); if(s-d[q]*2-d[p]<sum) sum=s-d[q]*2-d[p],ans=p; p=lca(x,z); if(s-d[q]*2-d[p]<sum) sum=s-d[q]*2-d[p],ans=p; p=lca(y,z); if(s-d[q]*2-d[p]<sum) sum=s-d[q]*2-d[p],ans=p; printf("%d %d\n",ans,sum); } }