zoukankan      html  css  js  c++  java
  • [做题记录-数据结构]Luogu P7889 「MCOI-06」Eert Tuc Knil 题解

    题意

    给定一颗 (n) 个节点有根树,第 (i) 节点权值为 (a_i)

    在这个树上支持一种询问:

    给定节点 (u) 和参数 (x)假如 所有节点点权加 (x)在这种情况下,求: 对于所有完全在 (u) 子树内并包含 (u) 的连通点集,权值之和最大可能为多少?

    (n leq 10^6)

    题解

    考虑一个( ext{dp})(f_x = val_x +sum max{f_y, 0})

    可以把查询离线, 然后只剩下加法。然后考虑如何维护加法。

    先对原树进行一次(dp), 然后可以转移的边视为存在, 否则不存在。每次找到一条不存在的边使得其存在即可维护答案。

    一条边不存在当且仅当其连接的连通块权值小于(0)。那么把连通块按照(frac{-val}{sz})排序, 每次取出最小的, 判断是否可以连上, 执行合并即可。

    然后现在的问题是如何快速进行合并和维护答案。

    维护答案的部分所需要的是维护一个点所连接的子树内的联通块的和以及大小。可以维护一个联通块的最高点, 这样的话就是执行一次链加。

    那么现在就是要做链加和单点查, 可以树剖(log^2)

    换成子树查可以做到一个(log)

    #include <bits/stdc++.h>
    
    using namespace std;
    
    using ll = long long;
    using ull = unsigned long long;
    
    template<typename T>
    inline void read(T &x) {
    	x = 0; char a = getchar(); bool f = 0;
    	for(; ! isdigit(a); a = getchar()) if(a == '-') f = 1;
    	for(; isdigit(a); a = getchar()) x = x * 10 + a - '0';
    	if(f) x = -x;	
    } 
    
    #define lep(i, l, r) for(int i = (l); i <= (r); i ++) 
    #define rep(i, l, r) for(int i = (r); i >= (l); i --) 
    
    const int N = 1e6 + 10;
    const ll Lim = 1e13;
    
    int n, m;
    
    struct BIT {
    	ll c[N];
    	#define lowbit(x) (x & -x)
    	void upd(int x, ll v) {
    		for(; x <= n; x += lowbit(x)) c[x] += v;
    	}
    	ll ask(int x) {
    		ll res = 0;
    		for(; x; x -= lowbit(x)) res += c[x];
    		return res;
    	}
    	ll qry(int l, int r) {
    		return ask(r) - ask(l - 1);
    	}
    } c1, c2;
    
    int Fa[N];
    inline int find(int x) { return x == Fa[x] ? x : Fa[x] = find(Fa[x]); }
    
    int fa[N];
    vector<int> e[N];
    struct Qry {
    	int id, x;
    	ll v;
    } q[N];
    
    ll val[N];
    int dfn[N], sz[N];
    
    void dfs(int x) {
    	dfn[x] = ++ dfn[0];
    	sz[x] = 1;
    	for(int y : e[x]) dfs(y), sz[x] += sz[y];
    }
    
    void modify(int x, int y, ll v, int tv) {
    	c1.upd(dfn[x], v);
    	c2.upd(dfn[x], tv);
    	y = fa[y];
    	if(y) {
    		c1.upd(dfn[y], -v);
    		c2.upd(dfn[y], -tv);
    	}
    }
    
    struct Node {
    	ll v; int x;
    	Node() {}
    	Node(ll _v, int _x) : v(_v), x(_x) {}
    	inline bool operator <(const Node &t) const {
    		return v != t.v ? v > t.v : x < t.x;	
    	}
    	inline bool operator ==(const Node &t) const {
    		return v == t.v && x == t.x;
    	}
    } ;
    
    struct Queue {
    	priority_queue<Node> q1, q2;
    	void push(Node v) {
    		q1.push(v);
    	}
    	void erase(Node v) {
    		q2.push(v);
    	}
    	Node top() {
    		while(q1.size() && q2.size() && q1.top() == q2.top()) q1.pop(), q2.pop();
    		return q1.top();
    	}
    	inline int size() {
    		return q1.size() - q2.size();
    	}
    } Q;
    
    ll ans[N];
    
    void link(int x) {
    	ll sum = c1.qry(dfn[x], dfn[x] + sz[x] - 1);
    	int ssz = c2.qry(dfn[x], dfn[x] + sz[x] - 1);
    	int t = find(fa[x]);
    	modify(fa[x], t, sum, ssz);
    	Fa[x] = t;
    	if(t != 1) {
    		Q.push( Node( ceil (1.0 * (- c1.qry(dfn[t], dfn[t] + sz[t] - 1)) / c2.qry(dfn[t], dfn[t] + sz[t] - 1)  + 1e-9), t ) );
    	}
    }
    
    int main() {
    	read(n); read(m);
    	lep (i, 2, n) read(fa[i]), e[fa[i]].push_back(i);
    	lep (i, 1, n) read(val[i]);
    	lep (i, 1, m) {
    		read(q[i].x); read(q[i].v); q[i].id = i;
    	}
    	lep (i, 1, n) val[i] -= Lim;
    	dfs(1);
    	lep (i, 1, n) Fa[i] = i, modify(i, i, val[i], 1); 
    	lep (i, 1, m) q[i].v += Lim;
    	sort(q + 1, q + 1 + m, [] (Qry a, Qry b) { return a.v < b.v; } );
    	lep (i, 2, n) {
    		Q.push( Node(- val[i] / 1, i) );
    	}
    	lep (i, 1, m) {
    		while(Q.size() && Q.top().v <= q[i].v) {
    			Node tmp = Q.top();
    			int fx = fa[tmp.x];
    			Q.erase(tmp);
    			fx = find(fx);
    			if(fx != 1) {
    				Q.erase( Node( ceil (1.0 * (- c1.qry(dfn[fx], dfn[fx] + sz[fx] - 1)) / c2.qry(dfn[fx], dfn[fx] + sz[fx] - 1) + 1e-9), fx ) );
    			}
    			link(tmp.x);
    		}
    		ans[q[i].id] = c1.qry(dfn[q[i].x], dfn[q[i].x] + sz[q[i].x] - 1) + c2.qry(dfn[q[i].x], dfn[q[i].x] + sz[q[i].x] - 1) * q[i].v;
    	}
    	lep (i, 1, m) printf("%lld
    ", ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    IIS打开本地站点时,无法访问本地json文件的解决办法
    几种流行的前端框架(BootStrap、Layui、Element-UI、Mint UI、Angular、Vue.js、React)
    六大排序算法:插入排序、希尔排序、选择排序、冒泡排序、堆排序、快速排序
    SpringBoot框架开发的优秀的项目「值得收藏学习」
    jmeter接口之json提取器应用
    【设计模式(23)】行为型模式之访问者模式
    【设计模式(22)】行为型模式之模板模式
    【设计模式(21)】行为型模式之策略模式
    HTML回忆笔记,给那些忘了但又没完全忘的人准备的
    vscode创建html文件使用"!+tab"不起作用的解决方法
  • 原文地址:https://www.cnblogs.com/clover4/p/15371835.html
Copyright © 2011-2022 走看看