POJ 2114 - Boatherds
原题地址:http://poj.org/problem?id=2114
题目大意:
给定一棵点数为\(n~(n \le 10000)\)的无根树,路径上有权值,给出m组询问($m \le 100$),每组询问给出一个k,问树中是否存在长度为k的链。题目是多case
题目分析:
这是第二次写树分治,细节想清楚真的很重要啊。。。写了两天才写过,接下来说一说算法流程和需要注意的细节吧
首先读入、建图等等等等。。
然后是分治过程:
0.如果当前处理的这棵树的size很小了,调用暴力解决,否则继续执行(这相当于边界处理)
1.找出当前要处理的树的重心作为分治点
2.算出重心到这棵树中每个点的距离,扫出来是否有两个点的距离和等于要询问的值,有则加上对数
3.将重心发出的所有边断开,计算每棵子树中到重心距离和为k的点对,在答案中减去
4.递归处理所有子树,根据最终得到的个数判断是否存在
分治过程看起来很简单,但是有几个细节需要注意:断边的时候断开邻接表需要小心。每一次递归我们都需要初始化一些变量,但是每次全部初始化的代价过于高昂,而且会影响到当前树中没有的节点,每次初始化都BFS一遍过于麻烦,所有可以开若干个vector表示当前递归处理的子树中的点,然后就可以减少复杂度。计算距离之后需要排序去重以便高效地计算出要求的值。
(准备省选过于忙碌了一直没来得及写什么总结……学了不少新知识回头都得抓紧总结了)
1 //date 20140417 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 7 const int maxn = 10500; 8 const int INF = 0x7FFFFFFF; 9 const int r1 = 2; 10 11 using namespace std; 12 typedef vector<int> array; 13 typedef array::iterator iter; 14 typedef vector<array>::iterator viter; 15 16 inline int getint() 17 { 18 int ans(0); char w = getchar(); 19 while(w < '0' || '9' < w)w = getchar(); 20 while('0' <= w && w <= '9') 21 { 22 ans = ans * 10 + w - '0'; 23 w = getchar(); 24 } 25 return ans; 26 } 27 28 inline int innew(int &a, int b){if(a < b){a = b; return 1;}return 0;} 29 inline int denew(int &a, int b){if(a > b){a = b; return 1;}return 0;} 30 31 struct edge 32 { 33 int v, w, next; 34 }E[maxn << 1]; 35 int a[maxn], nedge; 36 int n; 37 int ask[maxn], ans[maxn], nsk; 38 39 vector<array> P; 40 array tmp; 41 42 inline void add(int u, int v, int w) 43 { 44 E[++nedge].v = v; 45 E[nedge].w = w; 46 E[nedge].next = a[u]; 47 a[u] = nedge; 48 } 49 50 namespace d_c 51 { 52 int yff, dis[maxn], list[maxn], size[maxn], p[maxn]; 53 int q[maxn], st, ed; 54 int d[maxn], last, now[maxn], had[maxn]; 55 int tlist[maxn], ttot, plist[maxn]; 56 57 inline int getcend(int k, int yff) 58 { 59 for(iter i = P[k].begin(); i != P[k].end(); ++i) 60 { 61 size[*i] = p[*i] = 0; now[*i] = a[*i]; 62 } 63 size[d[last = 1] = P[k][0]] = 1; 64 while(last) 65 { 66 int i = d[last], j = now[i]; 67 if(!j) 68 { 69 if(--last) size[d[last]] += size[i]; 70 continue; 71 } 72 if(!size[E[j].v]) 73 { 74 size[d[++last] = E[j].v] = 1; 75 p[E[j].v] = i; 76 } 77 now[i] = E[j].next; 78 } 79 int Max, ans, Min = INF; 80 for(iter i = P[k].begin(); i != P[k].end(); ++i) 81 { 82 Max = yff - size[*i]; 83 for(int j = a[*i]; j; j = E[j].next)if(p[*i] != E[j].v) 84 innew(Max, size[E[j].v]); 85 if(denew(Min, Max))ans = *i; 86 } 87 if(p[ans])size[p[ans]] = yff - size[ans]; 88 return ans; 89 } 90 91 inline void brutf(int k, int yff) 92 { 93 for(iter i = P[k].begin(); i != P[k].end(); ++i) 94 { 95 for(iter j = P[k].begin(); j != P[k].end(); ++j)dis[*j] = list[*j] = 0; 96 int st = 0, ed = 1, tot; 97 q[dis[*i] = 1] = *i; 98 while(st < ed) 99 { 100 int x = q[++st]; 101 for(int i = a[x]; i; i = E[i].next)if(!dis[E[i].v]) 102 dis[q[++ed] = E[i].v] = dis[x] + E[i].w; 103 } 104 for(iter j = P[k].begin(); j != P[k].end(); ++j) 105 for(int need = 1; need <= nsk; ++need) 106 ans[need] += (dis[*j] == ask[need] + 1) << 1; 107 } 108 } 109 110 inline void main(int k) 111 { 112 yff = P[k].size(); 113 if(yff <= r1){brutf(k, yff); return;} 114 int cend = getcend(k, yff); 115 for(iter i = P[k].begin(); i != P[k].end(); ++i) dis[*i] = had[*i] = 0; 116 st = 0; ed = 1; int tot; 117 list[dis[q[1] = cend] = tot = 1] = 1; 118 while(st < ed) 119 { 120 int x = q[++st]; 121 for(int i = a[x]; i; i = E[i].next)if(!dis[E[i].v]) 122 { 123 list[++tot] = dis[q[++ed] = E[i].v] = dis[x] + E[i].w; 124 } 125 } 126 127 sort(list + 1, list + tot + 1); 128 tlist[plist[1] = ttot = 1] = list[1]; 129 for(int i = 2; i <= tot; ++i) 130 { 131 if(list[i] == list[i - 1])++plist[ttot]; 132 else {tlist[++ttot] = list[i]; plist[ttot] = 1;} 133 } 134 135 for(int need = 1; need <= nsk; ++need) 136 { 137 int j = ttot; 138 for(int i = 1; i <= ttot; ++i) 139 { 140 while(j && (tlist[j] + tlist[i] > ask[need] + 2))--j; 141 if(!j)break; 142 if(tlist[j] + tlist[i] == ask[need] + 2) 143 { 144 if(j != i)ans[need] += plist[i] * plist[j]; 145 else ans[need] += plist[i] * (plist[i] - 1); 146 } 147 } 148 } 149 150 for(int i = a[cend]; i; i = E[i].next) 151 { 152 int sign = 0; 153 if(a[E[i].v] == (i ^ 1)){a[E[i].v] = E[i ^ 1].next;} 154 else 155 { 156 int last; 157 for(int j = a[E[i].v]; j != (i ^ 1); j = E[j].next) last = j; 158 E[last].next = E[i ^ 1].next; 159 } 160 tmp.clear(); 161 st = 0; ed = 1; q[had[E[i].v] = 1] = E[i].v; 162 tmp.push_back(E[i].v); 163 list[tot = 1] = dis[E[i].v]; 164 while(st < ed) 165 { 166 int x = q[++st]; 167 for(int j = a[x]; j; j = E[j].next) 168 if(!had[E[j].v]){tmp.push_back(E[j].v); had[E[j].v] = 1; q[++ed] = E[j].v; list[++tot] = dis[E[j].v];} 169 } 170 sort(list + 1, list + tot + 1); 171 tlist[plist[1] = ttot = 1] = list[1]; 172 for(int w = 2; w <= tot; ++w) 173 { 174 if(list[w] == list[w - 1])++plist[ttot]; 175 else {tlist[++ttot] = list[w]; plist[ttot] = 1;} 176 } 177 178 for(int need = 1; need <= nsk; ++need) 179 { 180 int j = ttot; 181 for(int w = 1; w <= ttot; ++w) 182 { 183 while(j && (tlist[j] + tlist[w] > ask[need] + 2))--j; 184 if(!j)break; 185 if(tlist[w] + tlist[j] == ask[need] + 2) 186 { 187 if(j != w)ans[need] -= plist[w] * plist[j]; 188 else ans[need] -= plist[w] * (plist[w] - 1); 189 } 190 } 191 } 192 193 P.push_back(tmp); 194 main(P.size() - 1); 195 } 196 197 } 198 } 199 200 int main() 201 { 202 while(true) 203 { 204 n = getint(); 205 if(!n)break; 206 P.clear(); tmp.clear(); 207 memset(a, 0, sizeof a); 208 memset(ans, 0, sizeof ans); 209 nedge = 1; 210 211 for(int i = 1; i <= n; ++i)tmp.push_back(i); 212 P.push_back(tmp); 213 214 for(int i = 1; i <= n; ++i) 215 { 216 int x, w; 217 while(true) 218 { 219 x = getint(); 220 if(!x)break; 221 w = getint(); 222 add(i, x, w); add(x, i, w); 223 } 224 } 225 nsk = 0; 226 while(true) 227 { 228 ask[++nsk] = getint(); 229 if(!ask[nsk]){--nsk; break;} 230 } 231 d_c::main(0); 232 for(int i = 1; i <= nsk; ++i)printf("%s\n", ans[i] > 0 ? "AYE" : "NAY"); 233 printf(".\n"); 234 } 235 236 return 0; 237 }