bzoj 1787: [Ahoi2008]Meet 緊急集合【樹鏈剖分lca】
阿新 • • 發佈:2018-09-14
== ace dfs tdi 但是 stream -- max i++
對於三個點求最小路徑長度和,答案肯定在某兩個點的lca上,因為如果把集合點定在公共lca上,一定有兩個點匯合後再一起上到lca,這樣顯然不如讓剩下的那個點下來
這個lca可能是深度最深的……但是我懶得證了,反正只有三個lca,每個都求一遍然後取個max就好啦
#include<iostream> #include<cstdio> using namespace std; const int N=500005; int n,m,h[N],cnt,de[N],si[N],fa[N],hs[N],fr[N]; struct qwe { int ne,to; }e[N<<1]; int read() { int r=0,f=1; char p=getchar(); while(p>‘9‘||p<‘0‘) { if(p==‘-‘) f=-1; p=getchar(); } while(p>=‘0‘&&p<=‘9‘) { r=r*10+p-48; p=getchar(); } return r*f; } void add(int u,int v) { cnt++; e[cnt].ne=h[u]; e[cnt].to=v; h[u]=cnt; } void dfs1(int u,int fat) { fa[u]=fat; de[u]=de[fat]+1; si[u]=1; for(int i=h[u];i;i=e[i].ne) if(e[i].to!=fat) { dfs1(e[i].to,u); si[u]+=si[e[i].to]; if(si[e[i].to]>si[hs[u]]) hs[u]=e[i].to; } } void dfs2(int u,int top) { fr[u]=top; if(!hs[u]) return; dfs2(hs[u],top); for(int i=h[u];i;i=e[i].ne) if(e[i].to!=fa[u]&&e[i].to!=hs[u]) dfs2(e[i].to,e[i].to); } int lca(int u,int v) {//cerr<<u<<" "<<v<<endl; for(;fr[u]!=fr[v];de[fr[u]]>de[fr[v]]?u=fa[fr[u]]:v=fa[fr[v]]); return de[u]<de[v]?u:v; } int main() { n=read(),m=read(); for(int i=1;i<n;i++) { int x=read(),y=read(); add(x,y),add(y,x); } dfs1(1,0); dfs2(1,1); while(m--) { int x=read(),y=read(),z=read(),lc1=lca(x,y),lc2=lca(y,z),lc3=lca(z,x),lc,ans=1e9,p,nw;//cerr<<x<<" "<<y<<" "<<z<<endl; lc=lca(lc1,z);//cerr<<lc<<endl; nw=de[x]-de[lc1]+de[y]-de[lc1]+de[z]-de[lc]+de[lc1]-de[lc]; if(nw<ans) ans=nw,p=lc1; lc=lca(lc2,x);//cerr<<lc<<endl; nw=de[y]-de[lc2]+de[z]-de[lc2]+de[x]-de[lc]+de[lc2]-de[lc]; if(nw<ans) ans=nw,p=lc2; lc=lca(lc3,y);//cerr<<lc<<endl; nw=de[z]-de[lc3]+de[x]-de[lc3]+de[y]-de[lc]+de[lc3]-de[lc]; if(nw<ans) ans=nw,p=lc3; printf("%d %d\n",p,ans); } return 0; }
bzoj 1787: [Ahoi2008]Meet 緊急集合【樹鏈剖分lca】