Poj 1741 Tree
来源:互联网 发布:小白素材vip源码 编辑:程序博客网 时间:2024/04/30 12:31
树分治入门题
如果你要学习树分治,请按照以下步骤
首先你要知道什么是树的重心,并且能在dfs过程中找到树的重心
然后你要理解树分治的分治过程,能知道每一次分治的时候对于每一个子树都要找一次重心,并且能写出每次找重心的代码
最后是具体题面具体分析,知道如何在分治过程中统计答案
对于这个这个题来说,要统计的是树上路径和小于k的点对
我们考虑过重心的路径,记录
对于过重心的路径要统计的就是
然后对于这个
然后就好求了,具体见代码
#include<vector>#include<algorithm>#include<cstdio>#include<cstring>using namespace std;const int inf = 0x3f3f3f3f;const int maxn = 11234;vector<pair<int,int> >edge[maxn];void init(int n){ for(int i=0;i<=n;i++){ edge[i].clear(); }}void Link(int st,int ed,int v){ edge[st].push_back(make_pair(ed,v)); edge[ed].push_back(make_pair(st,v));}bool vis[maxn];int siz[maxn],msiz[maxn];int lener[maxn],len;int k;int calroot(int st,int fa,int all){ int ret = -1; siz[st] = 1,msiz[st] = 0; for(vector<pair<int,int> >::iterator it = edge[st].begin();it!=edge[st].end();it++){ int x = it->first; if(x != fa && !vis[x]){ int trot = calroot(x,st,all); if(ret==-1 || msiz[ret]>msiz[trot]) ret = trot; siz[st] += siz[x]; msiz[st] = max(msiz[st],siz[x]); } } msiz[st] = max(msiz[st],all - siz[st]); if(ret==-1 || msiz[ret]>msiz[st]) ret = st; return ret;}int getpair(){ int ret = 0; sort(lener,lener+len); int pos = len-1; for(int i=0;i<len;i++){ while(pos>=0 && lener[pos]+lener[i]>k){ pos--; } ret += max(pos-i,0); } return ret;}void getlener(int st,int fa,int v){ lener[len++] = v; for(vector<pair<int,int> >::iterator it = edge[st].begin();it!=edge[st].end();it++){ int x = it->first,tv = it->second; if(x != fa && vis[x]==false){ getlener(x,st,v+tv); } }}void outlener(){ for(int i=0;i<len;i++){ printf(i<len-1?"%d ":"%d|\n",lener[i]); }}int dfs(int st){ vis[st] = true; int ans = 0; len = 0; getlener(st,-1,0); ans += getpair(); for(vector<pair<int,int> >::iterator it = edge[st].begin();it!=edge[st].end();it++){ int x = it->first,v = it->second; if(vis[x]) continue; len = 0; getlener(x,st,v); ans -= getpair(); ans += dfs(calroot(x,st,siz[x])); } return ans;}int cal(int n){ memset(vis,0,sizeof(vis)); return dfs(calroot(1,0,n));}int main(){ int n; while(~scanf("%d %d",&n,&k) && (n||k)){ int x,y,v; init(n); for(int i=1;i<n;i++){ scanf("%d %d %d",&x,&y,&v); Link(x,y,v); } printf("%d\n",cal(n)); } return 0;}
ps:求重心的时候不要用全局变量感觉写起来顺畅很多
0 0
- POJ 1741 Tree
- POJ 1741 Tree
- 【POJ 1741】Tree
- poj-1741 Tree
- [POJ 1741]Tree
- poj 1741 bzoj1468 Tree
- POJ 1741Tree
- Poj 1741 Tree
- POJ 1741 Tree
- POJ 1741 Tree
- POJ 1741 Tree
- Poj 1741 Tree
- 【POJ】1741 Tree
- POJ 1741 Tree
- poj 1741Tree
- poj 1741 tree
- POJ 1741 Tree 笔记
- POJ 1741 Tree
- C/C++ 关于大小端模式
- UVA1594
- 前端学习总结(十七)React Native——移动开发的未来趋势
- 一段snmp代码
- SQLite 总结
- Poj 1741 Tree
- 倒排句子的单词
- 不惑JAVA之JAVA基础 - NIO (二)
- Qt5 QSqlDataBase很好的错误说明 关于连接
- android一些问题解决
- HZAU 1006 The Nearest Same Chocolate
- 关于GDCPC2016的反省
- tengine 淘宝 nginx
- 表单新增元素与属性