• 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/
  • 相关阅读:
    1.Spring Framework 5.0 入门篇
    Spring,Spring MVC,Spring Boot 三者比较
    函数式编程:函数作为变量和函数的计算结果
    函数式编程:面向可复用的map和pipeline机制的编程语言
    异常处理的本质
    Error handling in Swift does not involve stack unwinding. What does it mean?
    函数式编程介绍
    pure funtion
    函数式编程与命令式编程
    命令式编程是面向计算机硬件的抽象
  • 原文地址:https://www.cnblogs.com/xcysblog/p/9607719.html
Copyright © 2020-2023  润新知