zoukankan      html  css  js  c++  java
  • P3241 [HNOI2015]开店

    点分树小结

    点分树的题其实就是把点分治的询问点换成某几个点,询问换成多组,有时还会带修改,那么我们会发现,每次如果做点分治,找重心的过程都是一样的,所以我们先处理出所有的重心,将其分成不同的层数,将所有重心逐层连起来,避免重复找重心,从而进行修改信息或回答多组询问

    两个关键的性质:

    • 点分树最大深度是(log)级别的

    • 点分树上两点的(lca)在原树上两点之间的路径上

    因此我们可以利用这两个强力的性质,在点分树上用比较暴力的方法解决路径统计问题。

    对于这道题

    • 首先假设没有(l,r)的限制,询问某个点到其他所有点的距离之和,我们用点分树去做该如何做。

    便于理解,设三个数组

    (sum[0][x])表示点分树上(x)子树的所有点到x的距离和

    (sum[1][x])表示点分树上(x)子树的所有点到x点分树上父亲的距离和

    (siz[x])表示点分树上(x)子树大小

    显然对于询问的点(x),我们跳点分树上的父亲即可,初始时(ans)设为(sum[0][x]),也就是点分树(x)子树下方的贡献和

    跳点分树父亲时,当前跳到点(now)(点(now)要有父亲),(ans += sum[0][fa[now]] - sum[1][now] + (siz[fa[now]] - siz[now]) * Dis(x, fa[now]))

    这是在跳的过程中加上(x)上方的贡献。

    (sum[0][fa[now]] - sum[1][now])(fa)的除掉(now)的子树的点到(fa)的距离和,然而这些贡献还少一段,就是(fa)(x)之间的一段,所以要加上后面的那部分。

    解释一下那两个减法,其实都是除掉已经处理过的子树,(siz)可以做减法减去重复计算的,比较简单,注意(sum)需要开两个数组,(sum[0][fa[now]] - sum[1][now])不能写成(sum[0][fa[now]] - sum[0][now]),其实挺显然的,因为这两个数组的对象不同,第一种写法的两个数组全是到(fa)的距离和,而第二种写法是到(fa)和到(now)的距离和,所以不能用第二种方法去重

    • 现在有了(l,r)的限制

    其实就是再加一维(存成(vector)),存上子树中各点的信息就好了,按照年龄排序,距离做个前缀和,然后询问(l,r)也就相当于([0,r] - [0,l-1]),二分出(vector)(l-1,r)的位置即可。因为点分树每层节点的(vector)元素总和是(n),共(log)层,所以空间(nlogn),可以接受

    然后还有个小优化,(siz)其实不用单独存个(vector),用二分后(sum)(vector)的下标之差就能算出(siz),另外我点分树一直写树剖(lca),感觉比(ST)表预处理要快一点

    • 总结:其实最主要的就是那个式子,初始(ans = sum[0][x]), 点分树跳父亲时,(ans += sum[0][fa[now]] - sum[1][now] + (siz[fa[now]] - siz[now]) * Dis(x, fa[now])),其他的都是套路了

    代码

    #include <cmath>
    #include <ctime>
    #include <vector>
    #include <cctype>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define rint register int
    using namespace std;
    typedef long long ll;
    
    const int maxn = 1.5e5 + 10;
    const int inf = 0x3f3f3f3f;
    int n, q, A, maxsiz, tsiz, rt, cnt, head[maxn], v[maxn], Fa[maxn];
    int dep[maxn], dis[maxn], siz[maxn], son[maxn], top[maxn], fa[maxn];
    bool vis[maxn];
    ll lastans;
    
    struct Edge {
    	int to, nxt, val;
    }e[maxn << 1];
    
    struct Node {
    	int v; ll sum;
    	bool operator < (const Node &B) const {
    		return v < B.v;
    	}
    };
    vector < Node > vec[2][maxn];
    
    template <typename T> T read(register T x = 0, register bool f = 0, register char ch = getchar()) {
    	for(;!isdigit(ch);ch = getchar()) f = ch == '-';
    	for(; isdigit(ch);ch = getchar()) x = (x << 3) + (x << 1) + (ch & 15);
    	return f ? -x : x ;
    }
    
    void add(rint x, rint y, rint z) {
    	e[++cnt] = (Edge){y, head[x], z}, head[x] = cnt;
    }
    
    void dfs1(rint x, rint prt) {
    	fa[x] = prt, dep[x] = dep[prt] + 1, siz[x] = 1;
    	for(rint i = head[x], y;i;i = e[i].nxt) {
    		if((y = e[i].to) == prt) continue;
    		dis[y] = dis[x] + e[i].val;
    		dfs1(y, x);
    		siz[x] += siz[y];
    		if(!son[x] || siz[y] > siz[son[x]]) son[x] = y;
    	}
    }
    
    void dfs2(rint x, rint tp) {
    	top[x] = tp;
    	if(son[x]) dfs2(son[x], tp);
    	for(rint i = head[x], y;i;i = e[i].nxt) {
    		if((y = e[i].to) != fa[x] && y != son[x]) dfs2(y, y);
    	}
    }
    
    int Dis(rint a, rint b) {
    	rint x = a, y = b;
    	while(top[x] != top[y]) {
    		if(dep[top[x]] < dep[top[y]]) swap(x, y);
    		x = fa[top[x]];
    	}
    	x = dep[x] < dep[y] ? x : y;
    	return dis[a] + dis[b] - dis[x] * 2;
    }
    
    void getrt(rint x, rint prt) {
    	siz[x] = 1;
    	rint maxs = 0;
    	for(rint i = head[x], y;i;i = e[i].nxt) {
    		if(vis[y = e[i].to] || y == prt) continue;
    		getrt(y, x);
    		siz[x] += siz[y];
    		maxs = max(maxs, siz[y]);
    	}
    	maxs = max(maxs, tsiz - siz[x]);
    	if(maxs < maxsiz) maxsiz = maxs, rt = x;
    }
    
    void dfs(rint x, rint prt, rint sum) {
    	siz[x] = 1;
    	vec[0][rt].push_back((Node){v[x], sum});
    	if(Fa[rt]) vec[1][rt].push_back((Node){v[x], Dis(x, Fa[rt])});
    	for(rint i = head[x], y;i;i = e[i].nxt) {
    		if(vis[y = e[i].to] || y == prt) continue;
    		dfs(y, x, sum + e[i].val);
    		siz[x] += siz[y];
    	}
    }
    
    void solve(rint x) {
    	vis[x] = 1, dfs(x, 0, 0);
    	for(rint i = head[x], y;i;i = e[i].nxt) {
    		if(vis[y = e[i].to]) continue;
    		tsiz = siz[y], maxsiz = inf, getrt(y, x);
    		Fa[rt] = x;
    		solve(rt);
    	}
    }
    
    ll query(rint opt, rint x, rint l, rint r, ll &ss) {
    	rint lef = lower_bound(vec[opt][x].begin(), vec[opt][x].end(), (Node){l, 0}) - vec[opt][x].begin() - 1;
    	rint rig = upper_bound(vec[opt][x].begin(), vec[opt][x].end(), (Node){r, 0}) - vec[opt][x].begin() - 1;
    	ss = rig - lef;
    	ll ans = 0;
    	if(rig >= 0 && rig < (int) vec[opt][x].size()) ans += vec[opt][x][rig].sum;
    	if(lef >= 0 && lef < (int) vec[opt][x].size()) ans -= vec[opt][x][lef].sum;
    	return ans;
    }
    
    int main() {
    	n = read<int>(), q = read<int>(), A = read<int>();
    	for(rint i = 1;i <= n; ++i) v[i] = read<int>();
    	for(rint i = 1, x, y, z;i < n; ++i) {
    		x = read<int>(), y = read<int>(), z = read<int>();
    		add(x, y, z), add(y, x, z);
    	}
    	dfs1(1, 0), dfs2(1, 1);
    	tsiz = n, maxsiz = inf, getrt(1, 0), solve(rt);
    	for(rint i = 1;i <= n; ++i) {
    		sort(vec[0][i].begin(), vec[0][i].end());
    		sort(vec[1][i].begin(), vec[1][i].end());
    		for(rint j = 1;j < (int)vec[0][i].size(); ++j) vec[0][i][j].sum += vec[0][i][j - 1].sum;
    		for(rint j = 1;j < (int)vec[1][i].size(); ++j) vec[1][i][j].sum += vec[1][i][j - 1].sum;
    	}
    	for(rint i = 1, x, l, r;i <= q; ++i) {
    		x = read<int>(), l = (read<ll>() + lastans) % A, r = (read<ll>() + lastans) % A;
    		l > r ? swap(l, r) : void();
    		ll s1, s2;
    		lastans = query(0, x, l, r, s1);
    		for(rint now = x;Fa[now];now = Fa[now]) {
    			lastans += query(0, Fa[now], l, r, s2) - query(1, now, l, r, s1);
    			lastans += (s2 - s1) * Dis(x, Fa[now]);
    		}
    		printf("%lld
    ", lastans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Ubuntu通过ADB连接手机
    MyRolan (快速启动小工具)
    关闭QQ右下角弹窗小程序
    day23作业-韩明琰
    day18-20作业-韩明琰
    day14-16作业-韩明琰
    java中对于多态的理解
    day11作业-韩明琰
    day10作业-韩明琰
    day09_作业
  • 原文地址:https://www.cnblogs.com/Lour688/p/14279589.html
Copyright © 2011-2022 走看看