BZOJ4719: [Noip2016]天天爱跑步
由于此题考法独特,就成功地卡我这种菜鸡卡了整整 12 小时
关于部分分作法可参考 这里
这里只说 AC 做法
yy ,手玩都行不通,考虑用数学的方式表示一下此题要我们求什么
列出恰好被观测到的条件:
在 s 到 lca 段,d[s] - d[x] = w[x]
在 lca 到 t 段, d[s] + d[x] - 2 * d[lca] = w[x]
移项,得
d[s] = d[x] + w[x]
d[s] - 2 * d[lca] = w[x] - d[x]
这时候开始有各种奇奇怪怪的想法 什么邻接表存一下什么启发式合并并查集什么的
很快都能否掉
其实就是在 s 到 lca 段出现数字 d[s]
在 lca 到 t 段出现数字 d[s] - 2 * d[lca]
求 以 x 为根的子树中出现的这些数字中 (等于 w[x] + d[x] 的个数) + (等于 w[x] - d[x] 的个数)
觉得树上差分乱搞很可做?
差不多,但有些需要考虑的地方,
两种数字有些不太一样,一次 dfs 一起计算比较麻烦,那就 dfs 两次
开桶记录个数有点慢?没事时限不是很紧
w[x] - d[x] 会有负数?加个偏移量就好了
空间不太资瓷?vector 对每个点存所有的 tag ,时间?总共就 O(n) 级别的 tag
于是差不多可做了
感觉这题想到用式子表示很强啊,想到后边的统计个数也很不好想啊
还是手懒 + 没做过题
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cctype> #include<cstdio> #include<vector> #include<queue> #include<cmath> using namespace std; const int MAXN = 300005, DLT = 300000; struct EDGE{ int nxt, to; EDGE(int NXT = 0, int TO = 0) {nxt = NXT; to = TO;} }edge[MAXN << 1]; struct QUE{ int x, y, lca; }que[MAXN]; int n, m, totedge, lg; int head[MAXN], dtc[MAXN], rv[MAXN << 1]; int dep[MAXN], f[MAXN][21], v[MAXN << 1]; int ans[MAXN]; vector<int> bgn[MAXN], fnl[MAXN], dcr[MAXN]; inline int rd() { register int x = 0; register char c = getchar(); while(!isdigit(c)) c = getchar(); while(isdigit(c)) { x = x * 10 + (c ^ 48); c = getchar(); } return x; } inline void add(int x, int y) { edge[++totedge] = EDGE(head[x], y); head[x] = totedge; return; } inline void bfs() { queue<int> q; dep[1] = 1; q.push(1); while(!q.empty()) { int x = q.front(); q.pop(); for(int i = head[x]; i; i = edge[i].nxt) if(!dep[edge[i].to]) { int y = edge[i].to; f[y][0] = x; dep[y] = dep[x] + 1; q.push(y); for(int j = 1; j <= lg; ++j) if(dep[y] > (1 << j)) f[y][j] = f[f[y][j - 1]][j - 1]; } } return; } inline int lca(int x, int y) { if(dep[y] > dep[x]) swap(x, y); for(int i = lg; i >= 0; --i) if(dep[f[x][i]] >= dep[y]) x = f[x][i]; if(x == y) return x; for(int i = lg; i >= 0; --i) if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i]; return f[x][0]; } inline void init1() { for(int i = 1; i <= m; ++i) { bgn[que[i].x].push_back(dep[que[i].x] - 1); dcr[f[que[i].lca][0]].push_back(dep[que[i].x] - 1); } return; } void dfs(int x, int fa) { int tmp = v[dtc[x] + dep[x] - 1 + DLT]; for(int i = head[x]; i; i = edge[i].nxt) if(edge[i].to != fa) dfs(edge[i].to, x); vector<int>::iterator it; for(it = bgn[x].begin(); it != bgn[x].end(); ++it) ++v[(*it) + DLT]; for(it = dcr[x].begin(); it != dcr[x].end(); ++it) --v[(*it) + DLT]; ans[x] += v[dep[x] + dtc[x] - 1 + DLT] - tmp; return; } inline void init2() { for(int i = 1; i <= n; ++i) dcr[i].clear(); for(int i = 1; i <= m; ++i) { fnl[que[i].y].push_back(dep[que[i].x] - 1 - ((dep[que[i].lca] - 1) << 1)); dcr[que[i].lca].push_back(dep[que[i].x] - 1 - ((dep[que[i].lca] - 1) << 1)); } return; } void efs(int x, int fa) { int tmp = rv[dtc[x] - dep[x] + 1 + DLT]; for(int i = head[x]; i; i = edge[i].nxt) if(edge[i].to != fa) efs(edge[i].to, x); vector<int>::iterator it; for(it = fnl[x].begin(); it != fnl[x].end(); ++it) ++rv[(*it) + DLT]; for(it = dcr[x].begin(); it != dcr[x].end(); ++it) --rv[(*it) + DLT]; ans[x] += rv[dtc[x] - dep[x] + 1 + DLT] - tmp; return; } int main() { n = rd(); m = rd(); lg = (int)log2(n) + 1; register int xx, yy; for(int i = 1; i < n; ++i) { scanf("%d%d", &xx, &yy); add(xx, yy); add(yy, xx); } bfs(); for(int i = 1; i <= n; ++i) scanf("%d", &dtc[i]); for(int i = 1; i <= m; ++i) { scanf("%d%d", &que[i].x, &que[i].y); que[i].lca = lca(que[i].x, que[i].y); } init1(); dfs(1, 0); init2(); efs(1, 0); for(int i = 1; i <= n; ++i) printf("%d ", ans[i]); puts(""); return 0; }
禁止诸如开发者知识库/布布扣/码迷/学步园/马开东等 copy 他人博文乃至博客的网站转载
,用户转载请注明出处:https://www.cnblogs.com/xcysblog/