树上处理的问题总结

//hdu4607
//树的直径，树上最长的链的顶点的个数
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <iostream>
#include <cmath>
#include <vector>
#include <set>
#include <algorithm>
#include <queue>
typedef long long ll;
#define rep(i,a,b) for (int i = (a); i <= (b); ++i)
#define rep(i,a,b) for (int i = (a); i <= (b); ++i)
using namespace std;
const int N = 200010;
int k, node, ans, x, y, n , m, a[N], l[N], f[N], far[N], zzz[N];
vector<int> v[N], s[N];
bool b[N];
void dfs(int k,int cnt){
int mx1, mx2;
if (cnt > ans){
ans = cnt;
node = k;
}
b[k] = true;
for (auto i:s[k]){
if (!b[i]){
dfs(i, cnt+1);
}
}

}
int main() {
int T;
cin >> T;
rep (_,1,T){
cin >> n >> m;
rep (i,1,n){
s[i].clear();
}
rep (i, 1, n-1){
scanf("%d%d",&x, &y);
s[x].push_back(y);
s[y].push_back(x);
}
ans = 0;
memset(b,false,sizeof(b));
dfs(1,1);
memset(b,false,sizeof(b));
dfs(node,1);
cout << ans << endl;
//        rep(i,1,m){
//            scanf("%d",&k);
//            if (k <= ans)
//                cout << k-1 << endl;
//            else
//                cout << (k-ans)*2+ans-1 << endl;
//        }
}
return 0;
}

poj1655:

//poj1655:
//定义树的balance为删去顶点i之后的森林中顶点个数最大的值。求这个点(重心)与它的balance值
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <iostream>
#include <cmath>
#include <vector>
#include <set>
#include <algorithm>
#include <queue>
typedef long long ll;
#define rep(i,a,b) for (int i = (a); i <= (b); ++i)
#define rep(i,a,b) for (int i = (a); i <= (b); ++i)
using namespace std;
const int N = 2000010;
int ans, n , m, x, y, son[N], bal[N];
vector<int> v[N];
bool vis[N];
void dfs(int k){
vis[k] = true;
int i;
//for (auto i : v[k]){
for (int j = 0; j < v[k].size(); ++j){
i = v[k][j];
if (!vis[i]){
dfs(i);
son[k]+=son[i];
bal[k] = max(bal[k], son[i]);
}
}
if (n-son[k]>bal[k])
bal[k] = n-son[k];
}
int main() {
int T;
cin >> T;
rep (_,1,T){
cin >> n;
rep (i,1,n){
v[i].clear();
}
memset(bal,0,sizeof(bal));
rep (i, 1, n-1){
scanf("%d%d",&x, &y);
v[x].push_back(y);
v[y].push_back(x);
}
ans = 0;
memset(vis, false, sizeof(vis));
rep (i,1,n){
son[i] = 1;
}
dfs(1);
memset(vis,false,sizeof(vis));
//dfs2(1,1);
int mii = 1;
rep (i,2,n){
if (bal[i] < bal[mii]){
mii = i;
}
}
cout << mii << " " << bal[mii] << endl;
}
return 0;
}

poj1741:

//poj1655:
//定义树的balance为删去顶点i之后的森林中顶点个数最大的值。求这个点(重心)与它的balance值
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <iostream>
#include <cmath>
#include <vector>
#include <set>
#include <algorithm>
#include <queue>
typedef long long ll;
#define rep(i,a,b) for (int i = (a); i <= (b); ++i)
#define rep(i,a,b) for (int i = (a); i <= (b); ++i)
using namespace std;
const int N = 2010;
int ans, n , m, x, y, z, son[N], bal[N], d[N];
vector<int> v[N], dis[N];
bool vis[N];
int mi,mii,cnt;
void dfs(int root,int k,int fa){
son[k] = 1;
bal[k] = 0;

int i, cos;
//for (auto i : v[k]){
for (int j = 0; j < v[k].size(); ++j){
i = v[k][j];
cos = dis[k][j];
if (i != fa && !vis[i]){
dfs(root, i, k);
son[k]+=son[i];
bal[k] = max(bal[k], son[i]);
}
}
}
void dfs2(int root,int k,int fa){
//    vis[k] = true;
if (son[root]-son[k]>bal[k])//son[root]就是n啦，代表所有的顶点数，减掉之后就相当于删掉自己之后的父节点的那棵子树
bal[k] = son[root]-son[k];

int i;
//for (auto i : v[k]){
for (int j = 0; j < v[k].size(); ++j){
i = v[k][j];
if (i != fa && !vis[i]){
dfs2(root, i, k);
}
}
if (bal[k] < mi){
mii = k;
mi = bal[k];
}
}
void calcdis(int k,int cost,int fa){
d[++cnt] = cost;
int i, cos;
for (int j = 0; j < v[k].size(); ++j){
i = v[k][j];
cos = dis[k][j];
if (i != fa && !vis[i]){
calcdis(i, cost+cos, k);
}
}
}
int calc(int root,int cos_prim){
cnt=0;
calcdis(root,cos_prim,0);

sort(d+1,d+cnt+1);
int i = 1;
int j = cnt;
int tot = 0;
while (i < j){
while (d[i]+d[j]>m&&i<j)
j--;
tot+=j-i;
i++;
}
}
void work(int k){

mi = n+1;
dfs(k,k,0);
dfs2(k,k,0);

ans+=calc(mii, 0);
vis[mii] = true;
int i,cos;
//for (auto i : v[k]){
int root = mii;
for (int j = 0; j < v[root].size(); ++j){
i = v[root][j];
cos = dis[root][j];
if (!vis[i]){
ans-=calc(i,cos);
}
}
for (int j = 0; j < v[root].size(); ++j){
i = v[root][j];
if (!vis[i]){
work(i);
}
}

}
int main() {
while ((scanf("%d%d",&n,&m))!=EOF&&n+m>0){
rep (i,1,n){
v[i].clear();
dis[i].clear();
}
rep (i, 1, n-1){
scanf("%d%d%d",&x, &y, &z);
v[x].push_back(y);
dis[x].push_back(z);
v[y].push_back(x);
dis[y].push_back(z);
}
ans = 0;
memset(vis, false, sizeof(vis));
work(1);
memset(vis,false,sizeof(vis));
cout << ans << endl;

}
return 0;
}


bzoj 2152

//poj1655:
//定义树的balance为删去顶点i之后的森林中顶点个数最大的值。求这个点(重心)与它的balance值
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <iostream>
#include <cmath>
#include <vector>
#include <set>
#include <algorithm>
#include <queue>
typedef long long ll;
#define rep(i,a,b) for (int i = (a); i <= (b); ++i)
#define rep(i,a,b) for (int i = (a); i <= (b); ++i)
using namespace std;
const int N = 2010;
int ans, n , m, x, y, z, son[N], bal[N], d[N], cnt[4];
vector<int> v[N], dis[N];
bool vis[N];
int mi,mii;
void dfs(int k,int fa){//这个函数其实可以和getroot合并起来，就是为了求出子树的重心的(当我们知道这颗子树的大小的时候就可以融合了，分开更直观)
son[k] = 1;
bal[k] = 0;

int i, cos;
//for (auto i : v[k]){
for (int j = 0; j < v[k].size(); ++j){
i = v[k][j];
cos = dis[k][j];
if (i != fa && !vis[i]){
dfs(i, k);
son[k]+=son[i];
bal[k] = max(bal[k], son[i]);
}
}
}
void getroot(int root,int k,int fa){
//    vis[k] = true;
if (son[root]-son[k]>bal[k])//son[root]就是n啦，代表所有的顶点数，减掉之后就相当于删掉自己之后的父节点的那棵子树
bal[k] = son[root]-son[k];

int i;
//for (auto i : v[k]){
for (int j = 0; j < v[k].size(); ++j){
i = v[k][j];
if (i != fa && !vis[i]){
getroot(root, i, k);
}
}
if (bal[k] < mi){
mii = k;
mi = bal[k];
}
}
void calc(int k,int fa,int dist){
cnt[dist % 3]++;
int cos, i;
for (int j = 0; j < v[k].size(); ++j){
i = v[k][j];
cos = dis[k][j];
if (!vis[i] && i != fa){
calc(i, k, dist+cos);
}
}
}

void work(int k){
memset(cnt,0,sizeof(cnt));
mi = n+1;
dfs(k,0);
getroot(k,k,0);
calc(mii,0,0);
//ans += cnt[0]*(cnt[0]-1) + 1 + 2*cnt[1]*cnt[2];
ans+= cnt[0]*cnt[0] + 2*cnt[1]*cnt[2];//计算当前的这个重心上的树的值为3的路径有多少
vis[mii] = true;//然后把这个重心及它相连的边从树上删除掉
int i,cos;
//for (auto i : v[k]){
int root = mii;
for (int j = 0; j < v[root].size(); ++j){

i = v[root][j];
cos = dis[root][j];
if (!vis[i]){
memset(cnt,0,sizeof(cnt));
calc(i,0,cos);
ans-=cnt[0]*cnt[0] + 2*cnt[1]*cnt[2];//减去子树上计算的重复的数
work(i);
}
}
}
int gcd(int x,int y){
int t;
if (x < y) swap(x, y);
while (y != 0){
t = y;
y = x % y;
x = t;
}
return x;
}
int main() {
cin >> n;
rep (i,1,n){
v[i].clear();
dis[i].clear();
}
//    memset(bal,0,sizeof(bal));
rep (i, 1, n-1){
scanf("%d%d%d",&x, &y, &z);
v[x].push_back(y);
dis[x].push_back(z);
v[y].push_back(x);
dis[y].push_back(z);
}
ans = 0;
memset(vis, false, sizeof(vis));
work(1);
int g = gcd(ans, n*n);
printf("%d/%d\n",ans/g,n*n/g);

return 0;
}


posted @ 2017-06-20 20:56 ohazyi 阅读(...) 评论(...) 编辑 收藏