• BZOJ 3631 [JLOI2014]松鼠的新家 | 树上差分


    链接

    BZOJ 3631

    题解

    看起来是树剖?实际上树上差分就可以解决……

    当要给一条路径(u, v) +1的时候,给d[u] += 1, d[v] += 1, d[lca(u, v)] -= 1, d[fa[lca(u, v)]] -= 1。

    注意这道题中路径的终点是不 +1的。

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    using namespace std;
    typedef long long ll;
    #define enter putchar('
    ')
    #define space putchar(' ')
    template <class T>
    void read(T &x){
        char c;
        bool op = 0;
        while(c = getchar(), c > '9' || c < '0')
    	if(c == '-') op = 1;
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
    	x = x * 10 + c - '0';
        if(op) x = -x;
    }
    template <class T>
    void write(T x){
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    
    const int N = 300005;
    int n, a[N], ans[N], dep[N], stk[N], top, pos[N], seq[2 * N][20], tot, lg[2 * N], fa[N];
    int ecnt, adj[N], nxt[2 * N], go[2 * N];
    
    void add(int u, int v){
        go[++ecnt] = v;
        nxt[ecnt] = adj[u];
        adj[u] = ecnt;
    }
    void dfs(int u){
        seq[++tot][0] = u, pos[u] = tot, stk[++top] = u;
        for(int e = adj[u], v; e; e = nxt[e])
    	if(v = go[e], v != fa[u]){
    	    fa[v] = u, dep[v] = dep[u] + 1;
    	    dfs(v);
    	    seq[++tot][0] = u;
    	}
    }
    int Min(int u, int v){
        return dep[u] < dep[v] ? u : v;
    }
    void init(){
        for(int i = 1, j = 0; i <= tot; i++)
    	lg[i] = i == (1 << (j + 1)) ? ++j : j;
        for(int j = 1; (1 << j) <= tot; j++)
    	for(int i = 1; i + (1 << j) - 1 <= tot; i++)
    	    seq[i][j] = Min(seq[i][j - 1], seq[i + (1 << (j - 1))][j - 1]);
    }
    int lca(int u, int v){
        int l = pos[u], r = pos[v];
        if(l > r) swap(l, r);
        int j = lg[r - l + 1];
        return Min(seq[l][j], seq[r - (1 << j) + 1][j]);
    }
    void path_modify(int u, int v, int x){
        int anc = lca(u, v);
        ans[u] += x, ans[v] += x, ans[anc] -= x, ans[fa[anc]] -= x;
    }
    
    int main(){
    
        read(n);
        for(int i = 1; i <= n; i++) read(a[i]);
        for(int i = 1, u, v; i < n; i++)
    	read(u), read(v), add(u, v), add(v, u);
        dfs(1);
        init();
        for(int i = 1; i < n; i++)
    	path_modify(a[i], a[i + 1], 1), path_modify(a[i + 1], a[i + 1], -1);
        for(int i = top; i; i--)
    	ans[fa[stk[i]]] += ans[stk[i]];
        for(int i = 1; i <= n; i++)
    	write(ans[i]), enter;
    
        return 0;
    }
    
  • 相关阅读:
    SpringBoot结合ShardingSphere实现分库分表、读写分离
    SpringBoot结合ShardingSphere实现主从读写分离
    使用Sentinel实现Spring Cloud Gateway网关流量控制
    使用Sentinel实现热点参数限流
    对比学习UIKit和AppKit--入门级
    UIViewController
    C++的异常处理之一:throw是个一无是处的东西
    About Closure
    理解Objective C 中id
    关于文件压缩的一些小知识
  • 原文地址:https://www.cnblogs.com/RabbitHu/p/BZOJ3631.html
Copyright © 2020-2023  润新知