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

  

 

posted @ 2018-09-08 01:09  EvalonXing  阅读(150)  评论(0编辑  收藏  举报