zoukankan      html  css  js  c++  java
  • CodeForces 1178G: The Awesomest Vertex

    题目传送门:CF1178G

    题意简述:

    一棵 (n)(1le nle 2 imes 10^5))个点的有根树,第 (i) 个点有 (a_i)(b_i) 两个属性,初始时保证 (|a_i|,|b_i|le 5000)

    定义第 (i) 个点的祖先节点(包括其本身)集合为 (R(i))

    (v) 个点的权值定义为 (displaystyleleft|sum_{win R(v)}a_w ight| imesleft|sum_{win R(v)}b_w ight|)

    执行 (q)(1le qle 10^5))次操作,每个操作为如下两种操作之一:

    1. 给定 (u,x)(1le ule n)(1le xle 5000)):将 (a_u) 增加 (x)

    2. 给定 (u)(1le ule n)):输出 (u) 的子树中的最大权值。

    题解:

    定义第 (i) 个点的子树内的节点(包括其本身)集合为 (S(i))

    注意到 (b_i) 始终不会变化,不妨令 (displaystyleeta_u=left|sum_{vin R(u)}b_v ight|),注意 (eta_i) 是非负数;再令 (displaystylealpha_u=sum_{vin R(u)}a_v)

    考虑化简操作 2,要求的即是 (displaystylemax_{vin S(u)}{|alpha_v| imeseta_v})

    因为 (eta_i) 是非负数,所以进一步化简为 (displaystylemaxleft{max_{vin S(u)}{alpha_veta_v},-min_{vin S(u)}{alpha_veta_v} ight})

    需要维护区间中 (alpha_ieta_i) 的最大值和最小值,其中 (eta_i) 为固定的非负数,要支持区间 (alpha_i) 加一个正数。

    这是经典问题,考虑分块,每个块内只需支持全局加 (keta_i) 和查询全局最大最小值即可。

    转化为维护上下凸壳,询问时用斜率递减的直线去切凸壳,可以使用单调队列直接维护,非整块修改时重构上下凸壳即可。

    下面是代码,实现时要注意卡常,时间复杂度 (mathcal{O}(nlog n+qsqrt{n}))

    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <cmath>
    
    typedef long long LL;
    typedef double db;
    const int MN = 200005;
    const int MB = 1345;
    
    inline void ckmax(LL &x, const LL &y) { x = x < y ? y : x; }
    inline LL Abs(const LL &x) { return x < 0 ? -x : x; }
    
    int N, Q, faz[MN], A[MN], B[MN];
    std::vector<int> G[MN];
    LL X[MN], Y[MN];
    int ldf[MN], rdf[MN], dfc;
    void DFS(int u) {
    	int id = ldf[u] = ++dfc;
    	X[id] = X[ldf[faz[u]]] + B[u];
    	Y[id] = Y[ldf[faz[u]]] + A[u];
    	for (auto v : G[u]) DFS(v);
    	X[id] = Abs(X[id]);
    	Y[id] *= X[id];
    	rdf[u] = dfc;
    }
    
    int S, T, bel[MN], lb[MB], rb[MB], lenk[MB];
    int _id[MN], *idk[MB];
    int _que1[MN], *que1k[MB], ql1[MB], qr1[MB];
    int _que2[MN], *que2k[MB], ql2[MB], qr2[MB];
    int rk[MB], tag[MB];
    LL ans[MB];
    
    inline db Slope(const int &i, const int &j) {
    	if (X[i] == X[j]) {
    		if (Y[i] == Y[j]) return 0;
    		else if (Y[i] < Y[j]) return 1e99;
    		else return -1e99;
    	}
    	return (db)(Y[j] - Y[i]) / (X[j] - X[i]);
    }
    
    inline void Flush(const int &k) {
    	if (!tag[k]) return ;
    	int *que1 = que1k[k], *que2 = que2k[k];
    	int &l1 = ql1[k], &r1 = qr1[k];
    	int &l2 = ql2[k], &r2 = qr2[k];
    	while (l1 < r1 && Slope(que1[l1], que1[l1 + 1]) > -rk[k]) ++l1;
    	while (l2 < r2 && Slope(que2[r2 - 1], que2[r2]) > -rk[k]) --r2;
    	int p1 = que1[l1], p2 = que2[r2];
    	ans[k] = std::max(Y[p1] + rk[k] * X[p1], -Y[p2] - rk[k] * X[p2]);
    	tag[k] = 0;
    }
    
    inline void ReBuild(const int &k) {
    	int *id = idk[k], *que1 = que1k[k], *que2 = que2k[k];
    	int &l1 = ql1[k], &r1 = qr1[k];
    	int &l2 = ql2[k], &r2 = qr2[k];
    	l1 = l2 = 1, r1 = r2 = 0;
    	for (int I = 1; I <= lenk[k]; ++I) {
    		int i = id[I];
    		while (l1 < r1 && Slope(que1[r1 - 1], que1[r1]) < Slope(que1[r1], i)) --r1;
    		while (l2 < r2 && Slope(que2[r2 - 1], que2[r2]) > Slope(que2[r2], i)) --r2;
    		que1[++r1] = i, que2[++r2] = i;
    	}
    	tag[k] = 1, Flush(k);
    }
    
    int main() {
    	scanf("%d%d", &N, &Q);
    	for (int i = 2; i <= N; ++i)
    		scanf("%d", &faz[i]),
    		G[faz[i]].push_back(i);
    	for (int i = 1; i <= N; ++i) scanf("%d", &A[i]);
    	for (int i = 1; i <= N; ++i) scanf("%d", &B[i]);
    	DFS(1);
    	S = 150, T = (N - 1) / S + 1;
    	for (int i = 1; i <= N; ++i) bel[i] = (i - 1) / S + 1;
    	for (int i = 1; i <= N; ++i) _id[i] = i;
    	for (int i = 1; i <= T; ++i) {
    		lb[i] = (i - 1) * S + 1;
    		rb[i] = std::min(i * S, N);
    		lenk[i] = rb[i] - lb[i] + 1;
    		idk[i] = _id + lb[i] - 1;
    		que1k[i] = _que1 + lb[i] - 1;
    		que2k[i] = _que2 + lb[i] - 1;
    		auto cmp = [](int i, int j) { return X[i] < X[j]; };
    		std::sort(idk[i] + 1, idk[i] + lenk[i] + 1, cmp);
    		ReBuild(i);
    	}
    	while (Q--) {
    		int op, u;
    		scanf("%d%d", &op, &u);
    		int l = ldf[u], r = rdf[u];
    		int bl = bel[l], br = bel[r];
    		if (op == 1) {
    			int val;
    			scanf("%d", &val);
    			if (bl < br) {
    				for (int i = l; i <= rb[bl]; ++i) Y[i] += val * X[i];
    				for (int i = lb[br]; i <= r; ++i) Y[i] += val * X[i];
    				ReBuild(bl), ReBuild(br);
    				for (int k = bl + 1; k < br; ++k) rk[k] += val, tag[k] = 1;
    			}
    			else {
    				for (int i = l; i <= r; ++i) Y[i] += val * X[i];
    				ReBuild(bl);
    			}
    		}
    		if (op == 2) {
    			LL Ans = 0;
    			if (bl < br) {
    				for (int i = l; i <= rb[bl]; ++i) ckmax(Ans, Abs(Y[i] + rk[bl] * X[i]));
    				for (int i = lb[br]; i <= r; ++i) ckmax(Ans, Abs(Y[i] + rk[br] * X[i]));
    				for (int k = bl + 1; k < br; ++k) Flush(k), ckmax(Ans, ans[k]);
    			}
    			else for (int i = l; i <= r; ++i) ckmax(Ans, Abs(Y[i] + rk[bl] * X[i]));
    			printf("%lld
    ", Ans);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Lodash JS实用类库 数组操作 延时执行 功能强大
    7.【nuxt起步】-Nuxt与后端数据交互
    vue图片懒加载
    猎鹰与龙飞船基于 Linux,采用 C++、Chromium 与 JS 开发
    | 和 ||,& 和 && 的区别
    Linux安装.net core
    Linux下程序后台运行:nohup和&
    vuejs如何调试代码
    全局安装 Vue cli3 和 继续使用 Vue-cli2.x
    导入sass文件
  • 原文地址:https://www.cnblogs.com/PinkRabbit/p/CF1178G.html
Copyright © 2011-2022 走看看