树|图 分治

hdu 4670 Cube number on a tree

需要确定树的中心,使以中心为根的子树中节点数最大的尽可能小。存着当模板不错。。。
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef __int64 ll;
const int MAXN = 50005;
int n, K;
ll prim[50], Pi[MAXN];
int divd[MAXN][35], sm[MAXN][35];
map<ll,int> mmp;
struct _edge
{
	int v, nxt;
}e[MAXN*2];
int head[MAXN], cnt, del[MAXN];
void add(int u, int v)
{
	e[cnt].v = v; e[cnt].nxt = head[u]; head[u] = cnt++;
}
int sz[MAXN], mxsz[MAXN], seq[MAXN], ns, cs, ceq[MAXN];
void dfs(int u, int pre)
{
	sz[u] = 1;
	seq[ns++] = u;
	mxsz[u] = 0;
	for (int i = head[u];~i;i=e[i].nxt)
	{
		int v = e[i].v;
		if (v != pre && !del[v])
		{
			dfs(v,u);
			sz[u] += sz[v];
			mxsz[u] = max(mxsz[u], sz[v]);
		}
	}
}
int center(int u)
{
	ns = 0;
	dfs(u,-1);
	int mn = 0x3fffffff, res = 0; 
	for (int i = 0; i< ns; ++i)
	{
		int t = seq[i];
		mxsz[t] = max(mxsz[t], sz[u] - sz[t]);
		if (mxsz[t] < mn)
		{
			mn = mxsz[t];
			res = t;
		} 
	}
	return res;
}
void getdis(int u, int pre)
{
	ceq[cs++] = u;
	if (pre == -1)
		memcpy(sm[u], divd[u], 4*35);
	else
	{
		for (int i = 0; i< K; ++i)
			sm[u][i] = (sm[pre][i] + divd[u][i])%3;
	}	
	for (int i = head[u]; ~i; i = e[i].nxt)
	{
		int v = e[i].v;
		if (!del[v] && v!= pre)
			getdis(v,u);
	}
}
ll cal(int u)
{
	ll res = 0, a0 = 0;
	int flg = 1;
	mmp.clear();
	for (int i = 0; i< K; ++i)
	{
		if (divd[u][i] != 0) flg = 0;
		a0 = (a0<<2) + divd[u][i];
	}
	if (flg) ++res;
	mmp[a0] = 1;
	for (int i = head[u];~i;i=e[i].nxt)
	{
		int v = e[i].v;
		if (del[v]) continue;
		cs = 0;
		getdis(v, -1);
		for (int j = 0; j< cs; ++j)
		{
			a0 = 0;
			for (int c = 0; c < K; c++)
			{
				a0 = (a0<<2) + (3-sm[ceq[j]][c])%3;
			}
			res += mmp[a0];
		}
		for (int j = 0; j< cs; ++j)
		{
			a0 = 0;
			for (int c = 0; c < K; c++)
			{
				a0 = (a0<<2) + (sm[ceq[j]][c]+divd[u][c])%3;
			}
			mmp[a0]++;
		}
	}
	return res;
}
ll solve(int u)
{
	ll res;
	u = center(u);
	del[u] = 1;
	res = cal(u);
	for (int i = head[u]; ~i; i =e[i].nxt)
	{
		int v = e[i].v;
		if (!del[v]) res += solve(v);
	}
	return res;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
	while (~scanf("%d", &n))
	{
		memset(del, 0, sizeof del); 
		memset(head, -1, sizeof head);
		cnt = 0;
		scanf("%d", &K);
		for (int i = 0; i< K; ++i)
			scanf("%I64d", prim+i);
		for (int i = 1; i<= n; ++i)
		{
			scanf("%I64d", Pi+i);
			for (int j = 0; j< K; ++j)
			{
				divd[i][j] = 0;
				while (Pi[i] % prim[j] == 0)
				{
					Pi[i] /= prim[j];
					++divd[i][j];
					divd[i][j] %= 3;
				}
			}
		}
		for (int i = 1; i<n ; ++i)
		{
			int u, v;
			scanf("%d%d", &u, &v);
			add(u, v); add(v, u);
		}
		printf("%I64d\n", solve(1));
	}
	return 0;
}


poj 1741 Cube number on a tree

号称男人八题里的一员。相当给力
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 10005;
int n, K;
struct _edge
{
	int v, nxt, w;
}e[MAXN*2];
int head[MAXN], cnt, del[MAXN], ans;
void add(int u, int v, int w)
{
	e[cnt].v = v; e[cnt].nxt = head[u]; e[cnt].w = w; head[u] = cnt++;
}
int sz[MAXN], mxsz[MAXN], seq[MAXN], ns, deq[MAXN], ds;
void dfs(int u, int pre)
{
	sz[u] = 1;
	seq[ns++] = u;
	mxsz[u] = 0;
	for (int i = head[u];~i;i=e[i].nxt)
	{
		int v = e[i].v;
		if (v != pre && !del[v])
		{
			dfs(v,u);
			sz[u] += sz[v];
			mxsz[u] = max(mxsz[u], sz[v]);
		}
	}
}
int center(int u)
{
	ns = 0;
	dfs(u,-1);
	int mn = 0x3fffffff, res = 0; 
	for (int i = 0; i< ns; ++i)
	{
		int t = seq[i];
		mxsz[t] = max(mxsz[t], sz[u] - sz[t]);
		if (mxsz[t] < mn)
		{
			mn = mxsz[t];
			res = t;
		} 
	}
	return res;
}
void getdis(int u, int pre, int val)
{
	deq[ds++] = val;
	for (int i = head[u]; ~i; i=e[i].nxt)
	{
		int v = e[i].v;
		if (v == pre || del[v]) continue;
		getdis(v, u, val+e[i].w);
	}
}
int cal(int u, int w)
{
	int res = 0;
	ds = 0;
	getdis(u, -1, w);
	sort(deq, deq+ds);
	for (int bg=0,ed=ds-1; bg<ed;)
	{
		if (deq[bg]+deq[ed]<=K)
			res += ed-bg++;
		else
			--ed;
	}
	return res;
}
void solve(int u)
{
	u = center(u);	
	ans += cal(u, 0);
	del[u] = 1;
	for (int i = head[u]; ~i; i =e[i].nxt)
	{
		int v = e[i].v;
		if (!del[v])
		{
			ans -= cal(v, e[i].w);
			solve(v);
		}
	}
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
	while (~scanf("%d%d", &n, &K) && n+K)
	{
		memset(del, 0, sizeof del); 
		memset(head, -1, sizeof head);
		cnt = 0;
		for (int i = 1; i<n ; ++i)
		{
			int u, v, w;
			scanf("%d%d%d", &u, &v, &w);
			add(u, v, w); add(v, u, w);
		}
		ans = 0;
		solve(1);
		printf("%d\n", ans);
	}
	return 0;
}


hdu 4858 项目管理

图的分治
题意:n个点的连通图有m条边。每个点有权值,切两点间可能存在多条边。存在两种请求:⒈为某点增加权值;⒉计算与某点相邻点的权值和(若两点间存在多条边则计算多次)
按点的度进行划分,每个点向相邻且度数比它大的点引边。每个点带有两个变量w(该点权值)、s(与该点相邻的度较小点的权值和)
#include <cstdio>
#include <iostream>
#include <cmath>
#include <map>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int MAXN = 100100;
typedef __int64 LL;
#pragma comment(linker, "/STACK:1024000000,1024000000")
struct _nodeI
{
	int u, v, nxt;
}node[MAXN], mode[MAXN];
int head[MAXN], cnt, mead[MAXN], cmt;
int n, m, du[MAXN], w[MAXN], ss[MAXN];
void add(int u, int v)
{
	node[cnt].v = v; node[cnt].nxt = head[u];
	node[cnt].u = u;
	head[u] = cnt++;
}
void addm(int u, int v)
{
	mode[cmt].v = v; mode[cmt].nxt = mead[u];
	mead[u] = cmt++;
}
void init()
{
	cnt = cmt = 0;
	for(int i = 0; i<= n; ++i)
		head[i]=mead[i] = -1, du[i] = 0, w[i]=ss[i]=0;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
	int t, q;
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d%d", &n, &m);
		init();
		while (m--)
		{
			int a, b;
			scanf("%d%d", &a, &b);
			du[a]++; du[b]++;
			add(a, b);
		}
		for (int i = 0; i< cnt; ++i)
		{
			int u = node[i].u, v = node[i].v;
			// printf("%d %d %d %d\n", u, du[u], v, du[v]);
			if (du[u] == du[v])
			{
				if (u < v) addm(u, v);
				else addm(v, u);
			}
			else if (du[u] > du[v])
				addm(v, u);
			else addm(u, v);
		}
		scanf("%d", &q);
		while (q--)
		{
			int c, a, b;
			scanf("%d", &c);
			if (!c)
			{
				scanf("%d%d", &a, &b);
				w[a] += b;
				for (int i = mead[a]; ~i; i=mode[i].nxt)
					ss[mode[i].v] += b;
			}
			else
			{
				scanf("%d", &a);
				int ans = ss[a];
				for (int i = mead[a]; ~i; i=mode[i].nxt)
					ans += w[mode[i].v];
				printf("%d\n", ans);
			}
		}
	}
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值