国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Poj 1741 Tree

2019-11-08 19:26:51
字體:
來源:轉載
供稿:網友

傳送門

http://poj.org/PRoblem?id=1741


題目大意

給出一顆n 個節點,n?1 條邊的樹,詢問兩點(u,v) 滿足起簡單路徑的長度小于等于k 的方案數,k 為給定常數。


我的想法

考慮一顆樹,那么(u,v) 有兩種可能:要么過樹根,要么不過樹根x。 考慮點分治,如果過x 的話直接遞歸就好了;不過x 呢,我們可以把所有點到x 的距離d(u,x) 算出來,如果存在兩個點(u,v) 滿足dis(u,x)+dis(v,x)≤k 就滿足條件。但是可能會出現重復的情況,就是這兩個點在x 的同一顆子樹內,設連接這顆子樹與x 的邊的另一端點為y,此時他們滿足dis(u,y)+dis(v,y)+2dis(y,x)≤k ,判一下減掉就好了。 時間復雜度O(nlog2n) 另外,每次找的樹根要盡量是的子樹節點數的最大值最小,也就是找重心,否則如果出現一條鏈那就完了。


代碼

#include <cstdio>#include <cstring>#include <algorithm>#define REP(i,_begin,_end) for(int i=(_begin);i!=(_end);++i)template<class T>T min(const T &a,const T &b){return a < b ? a : b;}template<class T>T max(const T &a,const T &b){return a > b ? a : b;}template<class T>bool chkmin(T &a,const T &b){return a > b ? a=b, 1 : 0;}template<class T>bool chkmax(T &a,const T &b){return a < b ? a=b, 1 : 0;}const int SN = 10000 + 50;const int Inf = 0x3f3f3f3f;int head[SN], nxt[SN<<1], to[SN<<1], wei[SN<<1], tot;int size[SN], dis[SN], d[SN], ans, rt, cnt, n, m, k, sum;bool vis[SN];void Init();void Add(int, int, int);void GetRt(int, int);void GetDis(int, int);int Calc(int, int);void Doit(int);int main(){ int x, y, z; while(scanf("%d%d",&n,&k)!=EOF && (n||k)){ Init(); REP(i, 1, n) scanf("%d%d%d",&x,&y,&z), Add(x, y, z); sum=n, cnt=Inf, GetRt(1,0), Doit(rt); printf("%d/n",ans); } return 0;}void Init(){ memset(head, 0, sizeof head), memset(nxt, 0, sizeof nxt); memset(vis, false, sizeof vis), tot=ans=0;}void Add(int u,int v,int w){ nxt[++tot]=head[u];head[u]=tot;to[tot]=v;wei[tot]=w; nxt[++tot]=head[v];head[v]=tot;to[tot]=u;wei[tot]=w;}void GetRt(int u,int fa){ int mx = 0; size[u] = 1; for(int i=head[u];i;i=nxt[i]) if(!vis[to[i]] && to[i]!=fa){ GetRt(to[i], u); size[u] += size[to[i]]; chkmax(mx,size[to[i]]); } if(chkmin(cnt,max(mx,sum-size[u]))) rt = u;}void GetDis(int u,int fa){ dis[dis[0]++] = d[u]; for(int i=head[u];i;i=nxt[i]) if(to[i]!=fa && !vis[to[i]]) d[to[i]] = d[u]+wei[i], GetDis(to[i],u);}int Calc(int u,int x){ d[u]=x, dis[0]=1; GetDis(u, -1); std :: sort(dis+1, dis+dis[0]); int res = 0; for(int l=1,r=dis[0]-1;l<r;) if(dis[l]+dis[r]<=k) res += r-l, ++l; else --r; return res;}void Doit(int u){ ans += Calc(u,0); vis[u] = true; for(int i=head[u];i;i=nxt[i]) if(!vis[to[i]]){ ans -= Calc(to[i],wei[i]); sum = size[to[i]]; cnt=Inf, GetRt(to[i], u); Doit(rt); }}
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 涿鹿县| 宜兰县| 鄂尔多斯市| 鹤峰县| 丰城市| 松江区| 兴城市| 绩溪县| 通许县| 松滋市| 邢台市| 阿克陶县| 红桥区| 大埔区| 全椒县| 桦川县| 江津市| 榆中县| 五寨县| 织金县| 兖州市| 商洛市| 武义县| 达孜县| 汉沽区| 眉山市| 兴城市| 河池市| 子洲县| 邛崃市| 讷河市| 黎川县| 禄劝| 福泉市| 嘉善县| 新宾| 南漳县| 芷江| 玉龙| 琼中| 双柏县|