• 【LG3241】[HNOI2015]开店


    题面

    洛谷

    题解

    20pts

    直接暴力统计即可,复杂度(O(NQ))

    另20pts

    我们考虑动态点分治。

    怎么在原树上统计答案呢,我们对点(x)

    预处理出其子节点数目(s_0),其子树内每个点到(x)的距离和(s_1),以及其子树内每个点到(fa_x)的距离和(s_2)

    则每次我们暴跳父亲,显然(s_1[x]+sum s_1[fa]-s_2[p]+(s_0[fa]-s_0[p])*dis(fa,x))就是树上与(x)(lca)
    (fa)的所有点的距离之和,其中(fa)(p)的父亲,(p)为从(x)不断跳父亲直到根,那么只要不断枚举(fa),并不断往上跳并维护答案就可以了。

    然而上面只是为了方便理解,因为具体的计算不是这样的。我们对于(x)点内部的贡献可以直接计算,然后考虑往上跳。在上述的式子中如果一个点(p)(fa),那么答案就要减去(s_0[p]*dis(fa,x)+s_2[p]),如果一个点不是(x)那么答案就要加上(s_0[p]+dis(p,x)),然后每一个点都要加上自己的(sz_1)​。
    按这个规律在跳的时候不断加就好了。

    然后在点分树上维护这个东西就好了,正确性显然。

    再对于每个年龄维护一个东西,复杂度(O(20*Qlog n))

    100pts

    其实上面讲得差不多了。

    每个点维护一个(vector),对上述信息进行维护,将每个点的按年龄排序,统计距离的前缀和再分二分年龄即可。

    时间复杂度(O(Qlog^2 n)),空间复杂度(O(nlog n))

    代码

    C++11真的爽

    #include <iostream> 
    #include <cstdio> 
    #include <cstdlib> 
    #include <cstring> 
    #include <cmath> 
    #include <algorithm> 
    #include <vector> 
    using namespace std;
    inline int gi() {
        register int data = 0, w = 1;
        register char ch = 0;
        while (!isdigit(ch) && ch != '-') ch = getchar(); 
        if (ch == '-') w = -1, ch = getchar();
        while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
        return w * data; 
    } 
    typedef long long ll;
    const int INF = 1e9 + 5; 
    const int MAX_N = 1.5e5 + 5; 
    struct Graph { int to, cost, next; } e[MAX_N << 1]; int fir[MAX_N], e_cnt; 
    void clearGraph() { memset(fir, -1, sizeof(fir)); e_cnt = 0; } 
    void Add_Edge(int u, int v, int w) { e[e_cnt] = {v, w, fir[u]}; fir[u] = e_cnt++; } 
    struct Node { int age, dis; ll sum; } ; 
    inline bool operator < (const Node &l, const Node &r) { 
    	if (l.age == r.age) return l.dis == r.dis ? l.sum < r.sum : l.dis < r.dis; 
    	else return l.age < r.age; 
    } 
    vector<Node> vec[2][MAX_N]; 
    int pos[MAX_N], cnt, lg[MAX_N << 1], bin[20]; 
    int md[20][MAX_N << 1], dep[MAX_N]; 
    void dfs(int x, int f) { 
    	md[0][pos[x] = ++cnt] = dep[x]; 
    	for (int i = fir[x]; ~i; i = e[i].next) { 
    		int v = e[i].to; if (v == f) continue; 
    		dep[v] = dep[x] + e[i].cost; 
    		dfs(v, x); 
    		md[0][++cnt] = dep[x]; 
    	} 
    } 
    int dis(int u, int v) { 
    	int tmp = dep[u] + dep[v]; 
    	u = pos[u], v = pos[v]; 
    	if (u > v) swap(u, v); 
    	int k = lg[v - u + 1]; 
    	return tmp - (min(md[k][u], md[k][v - bin[k] + 1]) << 1ll); 
    } 
    int fa[MAX_N], size[MAX_N], centroid, rmx, sz; 
    bool used[MAX_N]; 
    void search_centroid(int x, int f) { 
    	int mx = 0; size[x] = 1; 
    	for (int i = fir[x]; ~i; i = e[i].next) { 
    		int v = e[i].to; if (v == f || used[v]) continue; 
    		search_centroid(v, x); size[x] += size[v]; 
    		mx = max(mx, size[v]); 
    	} 
    	mx = max(mx, sz - size[x]); 
    	if (mx < rmx) centroid = x, rmx = mx; 
    } 
    void Div(int x) { 
    	used[x] = 1; 
    	for (int i = fir[x]; ~i; i = e[i].next) { 
    		int v = e[i].to; if (used[v]) continue;
    		rmx = sz = size[v]; 
    		centroid = v; 
    		search_centroid(v, x); 
    		fa[centroid] = x; 
    		Div(centroid); 
    	} 
    } 
    ll query(int x, int a) { 
    	ll ans = 0; 
    	for (int i = x; i; i = fa[i]) {
    		int t = lower_bound(vec[0][i].begin(), vec[0][i].end(), (Node){a, 0, 0}) 
    			- vec[0][i].begin() - 1; 
    		ans += vec[0][i][t].sum + 1ll * t * dis(i, x); 
    	} 
    	for (int i = x; fa[i]; i = fa[i]) { 
    		int t = lower_bound(vec[1][i].begin(), vec[1][i].end(), (Node){a, 0, 0}) 
    			- vec[1][i].begin() - 1; 
    		ans -= vec[1][i][t].sum + 1ll * t * dis(fa[i], x); 
    	}
    	return ans; 
    } 
    int N, Q, A, age[MAX_N]; 
    int main () {
    #ifndef ONLINE_JUDGE 
        freopen("cpp.in", "r", stdin);
    #endif
    	clearGraph(); 
    	N = gi(), Q = gi(), A = gi(); 
    	for (int i = 1; i <= N; i++) age[i] = gi(); 
    	for (int i = 1; i < N; i++) { 
    		int u = gi(), v = gi(), w = gi(); 
    		Add_Edge(u, v, w), Add_Edge(v, u, w); 
    	} 
    	dfs(1, 0); 
        bin[0] = 1; for (int i = 1; i < 20; i++) bin[i] = bin[i - 1] << 1; 
    	for (int i = 1; bin[i] <= cnt; i++) 
    		for (int j = 1; j + bin[i] - 1 <= cnt; j++) 
    		    md[i][j] = min(md[i - 1][j], md[i - 1][j + bin[i - 1]]); 
    	for (int i = 2; i <= cnt; i++) lg[i] = lg[i >> 1] + 1; 
    	sz = rmx = N; 
    	search_centroid(1, 0); 
    	Div(centroid);
    
    	for (int x = 1; x <= N; ++x)
    		for (int o = x; o; o = fa[o]) { 
    			vec[0][o].push_back({age[x], dis(x, o), 0}); 
    			vec[1][o].push_back({age[x], dis(x, fa[o]), 0}); 
    		} 
    	for (int x = 1; x <= N; ++x) { 
    		for (int op = 0; op < 2; ++op) { 
    			vec[op][x].push_back({-1, 0, 0}); 
    			vec[op][x].push_back({INF, 0, 0}); 
    			sort(vec[op][x].begin(), vec[op][x].end()); 
    			for (auto ite = vec[op][x].begin() + 1; ite != vec[op][x].end(); ++ite)
    			    ite -> sum = (ite - 1) -> sum + ite -> dis; 
    		} 
    	} 
    	for (ll ans = 0; Q--; ) { 
    		int x = gi(), a = (ans + gi()) % A, b = (ans + gi()) % A; 
    		if (a > b) swap(a, b);
    		printf("%lld
    ", ans = query(x, b + 1) - query(x, a)); 
    	} 
        return 0; 
    } 
    
  • 相关阅读:
    网络摄像头Androi端显示(mjpeg)源码分析
    STM32F103 MQTT智能配网ESP07S WIFI 手机app控制继电器EMQ温湿度
    安装云服务器 ECS CentOS 7 图形化桌面
    PT100多路分布式LORA无线测温传感器工业设备老化温度监控记录仪
    把qt 程序打包成一个exe可以执行的文件
    STM32L051C8T6 HAL DMA IDLE串口不定长接收遇到的问题
    Project ERROR: Cannot run target compiler '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++'. Output:
    更换下平台
    H5单页面应用(SPA)架构总结
    财务系统功能开发要点概述
  • 原文地址:https://www.cnblogs.com/heyujun/p/10435927.html
Copyright © 2020-2023  润新知