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; }