P4175 [CTSC2008] 网络管理 Solution

Description

给定一棵 n n n 个点的树 T T T,点有点权 w i w_i wi.
定义 path ⁡ ( u , v ) \operatorname{path}(u,v) path(u,v) u → v u\to v uv 的路径上的点集.
执行 q q q 次操作分两种:

  • k u x k = 0 k=0 k=0):令 w u ← x w_u\gets x wux.
  • k u v k > 0 k>0 k>0):设可重集 S = { w i ∣ i ∈ path ⁡ ( u , v ) } S=\{w_i|i\in \operatorname{path}(u,v)\} S={wiipath(u,v)},求 S S S 中第 k k k 大的值,若 k > ∣ S ∣ k>|S| k>S 输出 invalid request!.

Limitations

1 ≤ n , q ≤ 8 × 10 4 1\le n,q\le 8\times 10^4 1n,q8×104
1 ≤ u , v ≤ n 1\le u,v\le n 1u,vn
1 ≤ w i , x ≤ 10 8 1\le w_i,x\le 10^8 1wi,x108
0 ≤ k ≤ n 0\le k\le n 0kn
2 s , 500 MB 2\text{s},500\text{MB} 2s,500MB

Solution

题目不强制在线,可以把询问全部离线下来.
看到求第 k k k 大,可以用整体二分,具体见 P2617.
不过这题是树上操作,所以分治中用的 BIT 要改成单点加,链和查询,套个树剖就好了.

由于树剖每次查询会剖出 O ( log ⁡ n ) O(\log n) O(logn) 个区间,整体二分本身的复杂度为 O ( n log ⁡ 2 n ) O(n \log^2 n) O(nlog2n),故时间复杂度为 O ( n log ⁡ 3 n ) O(n\log^3 n) O(nlog3n),不过常数很小,可以在 200 ms 200\text{ms} 200ms 内跑完.

Code

5.2 KB , 1.39 s , 26.61 MB    (c++20   with   o2) 5.2\text{KB},1.39\text{s},26.61\text{MB}\;\texttt{(c++20 with o2)} 5.2KB,1.39s,26.61MB(c++20 with o2)
代码是用两份拼接的,不会有人想看吧 .

#include <bits/stdc++.h>
using namespace std;

using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;

template<class T>
bool chmax(T &a, const T &b){
	if(a < b){ a = b; return true; }
	return false;
}

template<class T>
bool chmin(T &a, const T &b){
	if(a > b){ a = b; return true; }
	return false;
}

struct Node {
    int tp, val;
    int le, ri;
    int pos;
    
    Node(int _tp = 0, int _val = 0, int _le = 0, int _ri = 0, int _pos = 0):
        tp(_tp), val(_val), le(_le), ri(_ri), pos(_pos) {}
};

int lowbit(int x){
	return x & -x;
}

template<class T>
struct fenwick{
	int n;
	vector<T> c;
	
	fenwick() {}
	fenwick(int _n): n(_n){
		c.resize(n + 1);
	}
	
	fenwick(const vector<T> &a): n(a.size()){
		c.resize(n + 1);
		for(int i = 1; i <= n; i++){
			c[i] = c[i] + a[i - 1];
			int j = i + lowbit(i);
			if(j <= n) c[j] = c[j] + c[i];
		}
	}
	
	void add(int x, const T& v){
		for(int i = x + 1; i <= n; i += lowbit(i)) c[i] = c[i] + v;
	}
	
	T ask(int x){
		T ans{};
		for(int i = x + 1; i; i -= lowbit(i)) ans = ans + c[i];
		return ans;
	}
	
	T ask(int l, int r){
		return ask(r) - ask(l - 1);
	}
};

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	
	int n, m;
	cin >> n >> m;
	
	vector<int> a(n), nums;
	vector<Node> tasks, tmp;
	
	for (int i = 0; i < n; i++) {
	    cin >> a[i];
	    nums.push_back(a[i]);
	    tasks.emplace_back(1, a[i], -1, -1, i);
	}
	
	vector<vector<int>> g(n);
	for (int i = 0, u, v; i < n - 1; i++) {
		cin >> u >> v, u--, v--;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	
	vector<int> dep(n);
	vector<int> par(n), siz(n), son(n, -1);
    
    auto dfs = [&](auto&& self, int u, int fa) -> void {
    	siz[u] = 1, par[u] = fa;
    	for (auto v : g[u]) {
    		if (v == fa) continue;
    		dep[v] = dep[u] + 1;
    		self(self, v, u);
    		siz[u] += siz[v];
    		if (son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v;
    	}
    };
    
    int clock = 0;
    vector<int> dfn(n), top(n);
    
    auto dfs2 = [&](auto&& self, int u, int topf) -> void {
        dfn[u] = clock++;
    	top[u] = topf;
		if (~son[u]) self(self, son[u], topf);
		for (auto v : g[u]) {
			if (v == par[u] || v == son[u]) continue;
			self(self, v, v);
		}
    };
    
    dfs(dfs, 0, 0);
    dfs2(dfs2, 0, 0);
    
    fenwick<int> f(n);
    auto add = [&](int x, int y) { f.add(dfn[x], y); };
	auto ask = [&](int u, int v) {
		int ans = 0;
		while (top[u] != top[v]) {
		    if (dep[top[u]] < dep[top[v]]) swap(u, v);
		    ans += f.ask(dfn[top[u]], dfn[u]);
		    u = par[top[u]];
		}
		if (dep[u] > dep[v]) swap(u, v);
		ans += f.ask(dfn[u], dfn[v]);
		return ans;
	};
	
	auto lca = [&](int u, int v) {
		while (top[u] != top[v]) {
			if (dep[top[u]] < dep[top[v]]) swap(u, v);
			u = par[top[u]];
		}
		if (dep[u] > dep[v]) swap(u, v);
		return u;
	};
	
	auto dist = [&](int u, int v) {
	    return dep[u] + dep[v] - 2 * dep[lca(u, v)];	
	};
	
	int q = 0;
	for (int i = 0, k; i < m; i++) {
	    cin >> k;
	    if (k > 0) {
	        int l, r;
	        cin >> l >> r;
	        l--, r--;
	        tasks.emplace_back(0, k, l, r, q++);
	    }
	    else {
	        int p, v;
	        cin >> p >> v;
	        p--;
	        tasks.emplace_back(-1, a[p], -1, -1, p);
	        tasks.emplace_back(1, v, -1, -1, p);
	        nums.push_back(v);
	        a[p] = v;
	    }
	}
	
	sort(nums.begin(), nums.end());
	nums.erase(unique(nums.begin(), nums.end()), nums.end());
	
	vector<int> ans(q);
	for (auto &task : tasks) {
	    if (task.tp == 0) {
	    	int len = dist(task.le, task.ri) + 1;
	    	if (task.val < 1 || task.val > len) ans[task.pos] = -1;
	    	else task.val = len - task.val + 1;
	        continue;
	    }
	    
	    int p = lower_bound(nums.begin(), nums.end(), task.val) - nums.begin();
	    task.val = p;
	}

	auto solve = [&](auto &&self, int l, int r, int lo, int hi) -> void {
	    if (l >= r) {
	        return;
	    }
	    
	    if (lo == hi) {
    		for (int i = l; i <= r; i++) {
    			if (tasks[i].tp == 0 && ans[tasks[i].pos] != -1) {
    			    ans[tasks[i].pos] = lo;
    			}
    		}
    		return;
    	}
    	int mid = (lo + hi) / 2;
    	vector<Node> tl, tr;
    	
    	for (int i = l; i <= r; i++) {
    		if (tasks[i].tp) {
    			if (tasks[i].val <= mid) {
    			    add(tasks[i].pos, tasks[i].tp);
    			    tl.push_back(tasks[i]);
    			}
    			else {
    			    tr.push_back(tasks[i]);
    			}
    		}
    		else {
    			int cnt = ask(tasks[i].le, tasks[i].ri);
    			if (cnt >= tasks[i].val) {
    			    tl.push_back(tasks[i]);
    			}
    			else {
    			    tasks[i].val -= cnt;
    			    tr.push_back(tasks[i]);
    			}
    		}
    	}
    	for (int i = l; i <= r; i++) {
    		if (tasks[i].tp && tasks[i].val <= mid) {
    		    add(tasks[i].pos, -tasks[i].tp);
    		}
    	}
    	
    	copy(tl.begin(), tl.end(), tasks.begin() + l);
    	copy(tr.begin(), tr.end(), tasks.begin() + l + tl.size());
    	
    	self(self, l, l + tl.size() - 1, lo, mid);
    	self(self, l + tl.size(), r, mid + 1, hi);
	};
	
	solve(solve, 0, tasks.size() - 1, 0, nums.size() - 1);
	for (int i = 0; i < q; i++) {
	    if (ans[i] != -1) {
	        cout << nums[ans[i]] << '\n';
	    }
	    else cout << "invalid request!" << '\n';
	}
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值