1. 程式人生 > >bzoj [Usaco2010 Hol]cowpol 奶牛政壇【樹鏈剖分】

bzoj [Usaco2010 Hol]cowpol 奶牛政壇【樹鏈剖分】

clu int == fat void += char tdi ios

意識流虛樹
首先考慮只有一個黨派,那麽可以O(n)求樹的直徑,步驟是隨便指定一個根然後找距離根最遠點,然後再找距離這個最遠點最遠的點,那麽最遠點和距離這個最遠點最遠的點之間的距離就是直徑
那麽考慮多黨派,也這樣做,假如有一棵只有這個黨派的牛構成的虛樹,那麽求直徑也可以按照上面的做法
但是實際上並不用虛樹,直接在這個黨派的牛中1.隨便選一個牛然後找到距離它最遠的本黨派牛w 2.找到距離牛w最遠的本黨派牛,這之間的距離就是答案
求樹上距離用deep相減(樹剖求lca

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std; const int N=200005; int n,m,h[N],cnt,de[N],fa[N],si[N],hs[N],fr[N]; vector<int>a[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 x,int y) { for(;fr[x]!=fr[y];de[fr[x]]>de[fr[y]]?x=fa[fr[x]]:y=fa[fr[y]]); return de[x]<de[y]?x:y; } int dis(int x,int y) { return de[x]+de[y]-2*de[lca(x,y)]; } int main() { n=read(),m=read(); for(int i=1;i<=n;i++) { int x=read(),f=read(); if(f) add(f,i),add(i,f); a[x].push_back(i); } dfs1(1,0); dfs2(1,1); for(int i=1;i<=m;i++) { int mx=0,w,ans=0; for(int j=1;j<a[i].size();j++) { int di=dis(a[i][0],a[i][j]); if(di>mx) mx=di,w=a[i][j]; } for(int j=0;j<a[i].size();j++) if(a[i][j]!=w) { int di=dis(w,a[i][j]); if(di>ans) ans=di; }//cerr<<a[i][0]<<" "<<w<<" "; printf("%d\n",ans); } return 0; }

bzoj [Usaco2010 Hol]cowpol 奶牛政壇【樹鏈剖分】