1 条题解

  • 0
    @ 2026-5-6 15:49:59

    比较简单?

    考虑一个询问本质上只是将 [l,r][l, r] 里面的点缩起来然后再求 mst。

    注意到我们考虑建出克鲁斯卡尔重构树,那么只需要考虑删去 x,y[l,r]\forall x, y \in [l, r] 的 LCA 对应的贡献。

    然后这个就是典了,考虑支配对,我们进行 dsu on tree,然后每次考虑加入跨过子树的一对前驱和后驱 (x,y)(x, y),一共 nlognn \log n 组。

    然后这个 (x,y)(x, y) 的贡献视作二维平面上的点,转化为 2-side 矩形求颜色并,这个非常 Easy 啊,扫描线即可。

    复杂度 O(nlog2n)O(n\log^2 n)

    #include <bits/stdc++.h>
    #define rep(i, l, r) for (int i = l; i <= r; i ++)
    #define per(i, r, l) for (int i = r; i >= l; i --)
    #define int long long
    
    /*
    使い切って声に出そう
    单点加,区间查询。
    */
    using namespace std;
    
    typedef long long ll;
    const int _ = 3e5 + 5, mod = 998244353;
    int read() {
    	int x = 0, f = 1;
    	char ch = getchar();
    	while (ch < '0' || ch > '9') {
    		if (ch == '-') f = -1;
    		ch = getchar();
    	}
    	while (ch >= '0' && ch <= '9') {
    		x = x * 10 + ch - 48;
    		ch = getchar();
    	}
    	return x * f;
    }
    
    int tn, n, m, q, sum;
    int bits[_];
    void add (int x, int k) {
    	if (!x) return ;
    	for ( ; x <= n; x += x & -x) bits[x] += k;
    }
    int query (int x) {
    	int ret = 0;
    	for ( ; x; x -= x & -x) ret += bits[x];
    	return ret;
    } 
    
    vector<int> e[_];
    int v[_], sz[_], son[_];
    
    struct edge { int x, y, z; };
    vector<edge> g;
    vector<pair<int, int> > cv[_], qv[_];
    
    int anc[_], col[_], ans[_];
    int dfn[_], ed[_], dfc, id[_];
    int find (int x) { return x == anc[x] ? x : anc[x] = find(anc[x]); }
    set <int> s;
    
    signed main () {
    	tn = n = read(), m = read(), q = read();
    	rep(i, 1, n + n) anc[i] = i;
    	rep(i, 1, m) {
    		int x = read() + 1, y = read() + 1, z = read();
    		g.push_back({x, y, z});
    	}
    	auto kruskal = [&]() -> void {
    		sort(g.begin(), g.end(), [&](edge u, edge v) { return u.z < v.z; } );
    		for (auto [x, y, z] : g) {
    			x = find(x), y = find(y);
    			if (x != y) {
    				++ tn;
    				anc[x] = anc[y] = tn;	
    				sum += z, v[tn] = z;
    				e[tn].push_back(x), e[tn].push_back(y);
    			}
    		}
    	} ;
    	auto pre_dfs = [&](auto &self, int x) -> void {
    		dfn[x] = ++	dfc; 
    		id[dfc] = x;
    		sz[x] = 1;
    		for (int y : e[x]) {
    			self(self, y);
    			sz[x] += sz[y];
    			if (sz[y] > sz[son[x]]) son[x] = y;
    		}
    		ed[x] = dfc;
    	} ;
    	auto ins = [&](int x, int lca) -> void {
    		auto it	= s.lower_bound(x);
    		if (it != s.end()) cv[*it].push_back({x, lca});
    		if (it != s.begin()) cv[x].push_back({*prev(it), lca}); 
    	} ;
    	auto dsu = [&](auto &self, int x, int ty) -> void {
    		for (int y : e[x]) 
    			if (y ^ son[x]) self(self, y, 0);
    		if (son[x]) self(self, son[x], 1);
    		for (int y : e[x]) {
    			if (y == son[x]) continue ;
    			rep(i, dfn[y], ed[y]) ins(id[i], x);
    			rep(i, dfn[y], ed[y]) s.insert(id[i]);
    		}
    		if (!ty)
    			rep(i, dfn[x], ed[x]) s.erase(id[i]);
    		else if (x <= n) s.insert(x);
    	} ; 
    	kruskal();
    	pre_dfs(pre_dfs, tn);
    	dsu(dsu, tn, 0);
    	rep(i, 1, q) {
    		int l = read() + 1, r = read() + 1;
    		qv[r].push_back({l, i});
    	}
    	rep(r, 1, n) {
    		for (auto [l, c] : cv[r]) 
    			if (l > col[c]) { add(col[c], -v[c]); col[c] = l; add(col[c], v[c]); }
    		for (auto [l, id] : qv[r])
    			ans[id] = query(r) - query(l - 1);
    	}
    	rep(i, 1, q) printf("%lld\n", sum - ans[i]);
    	return 0;
    } 
    
    • 1

    信息

    ID
    10185
    时间
    4000ms
    内存
    1024MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者