zoukankan      html  css  js  c++  java
  • CERC 2014 (动态树+主席树)

    CERC 2014 Pork barrel

    Problem :
    n个点m条边有边权的无向图,有q个询问,每次询问权值在[L,R]内的边组成的最小生成树的权值和,强制在线。
    n <= 1000, m <= 100000, q <= 100000
    Solution :
    参考了网上的一份题解
    按照边权从大到小加入边,用LCT来维护最小生成树。再用一棵权值主席树,第i棵主席树记录表示权值大于等于 i 的边所构成的最小生成树边权和。
    对于每个询问[L, R]直接在第L棵主席树的[L ,R]区间内统计答案。

    对于每个询问[L, R],要将端点离散化成对应的边权表示,要注意离散化后的区间应被原来的区间包含,而不是包含原来的区间。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <string>
    #include <map>
    #include <vector>
    #include <queue>
    #include <cassert>
    using namespace std;
    #define f(i, x, y) for (int i = x; i <= y; ++i)
    #define fd(i, x, y) for (int i = x; i >= y; --i)
    #define rep(i, x, y) for (int i = x; i <= y; ++i)
    #define repd(i, x, y) for (int i = x; i >= y; --i)
    
    const int INF = 1e9 + 7;
    const int N = 300008;
    const int NN = N * 100;
    int n, m, q;
    
    void read(int &x)
    {
    	char ch;
    	for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar());
    	x = 0;
    	for (; ch >= '0' && ch <= '9'; ch = getchar())
    		 x = x * 10 + ch -  '0';
    }
    struct edge
    {
    	int u, v, w;
    	bool operator < (const edge &b) const
    	{
    		return w > b.w;
    	}
    }eg[N];
    int fa[N], c[N][2], val[N], mx[N], rev[N], st[N];
    int root[N], rtId[N], ls[NN], rs[NN];
    long long tag[NN];
    int num, total;
    int p[N];
    int tot;
    
    bool isroot(int x)
    {
    	return c[fa[x]][0] != x && c[fa[x]][1] != x;
    }
    void pushup(int x)
    {
    	int l = c[x][0], r = c[x][1];
    	mx[x] = x;
    	if (val[mx[l]] > val[mx[x]]) mx[x] = mx[l];
    	if (val[mx[r]] > val[mx[x]]) mx[x] = mx[r];
    }
    void pushdown(int x)
    {
    	int l = c[x][0], r = c[x][1];
    	if (rev[x])
    	{
    		if (l) rev[l] ^= 1;
    		if (r) rev[r] ^= 1;
    		rev[x] ^= 1;
    		swap(c[x][0], c[x][1]);
    	}
    }
    void rotate(int x)
    {
    	int y = fa[x], z = fa[y], l, r;
    	if (c[y][0] == x) l = 0; else l = 1; r = l ^ 1;
    	if (!isroot(y))
    	{
    		if (c[z][0] == y) c[z][0] = x; else c[z][1] = x;
    	}
    	fa[x] = z; fa[y] = x; fa[c[x][r]] = y;
    	c[y][l] = c[x][r]; c[x][r] = y;
    	pushup(y); pushup(x);
    }
    void splay(int x)
    {
    	int top = 0; st[++top] = x;
    	for (int i = x; !isroot(i); i = fa[i]) st[++top] = fa[i];
    	while (top) pushdown(st[top--]);
    	while (!isroot(x))
    	{
    		int y = fa[x], z = fa[y];
    		if (!isroot(y))
    		{
    			if (c[y][0] == x ^ c[z][0] == y) rotate(x);
    			else rotate(y);
    		}
    		rotate(x);
    	}
    }
    void access(int x)
    {
    	for (int t = 0; x; t = x, x = fa[x])
    	{
    		splay(x); 
    		c[x][1] = t;
    		pushup(x);
    	}
    }
    void rever(int x)
    {
    	access(x); splay(x); rev[x] ^= 1;
    }
    void link(int u, int v)
    {
    	rever(u); fa[u] = v;
    }
    void cut(int u, int v)
    {
    	rever(u); access(v); splay(v); fa[c[v][0]] = 0; c[v][0] = 0; pushup(v);
    }
    int find(int u)
    {
    	access(u); splay(u);
    	while (c[u][0]) u = c[u][0];
    	return u;
    }
    int query(int u, int v)
    {
    	rever(u); access(v); splay(v); return mx[v];
    }
    void build(int &rt, int l, int r)
    {
    	rt = ++total;
    	ls[rt] = rs[rt] = tag[rt] = 0;
    	if (l == r) return;
    	int m = l + r >> 1;
    	build(ls[rt], l, m);
    	build(rs[rt], m + 1, r);
    }
    void insert(int &rt, int last, int pos, int val, int l, int r)
    {
    	rt = ++total;
    	ls[rt] = ls[last]; rs[rt] = rs[last]; tag[rt] = tag[last];
    	if (l == r)
    	{
    		tag[rt] += val;
    		return;
    	}
    	int m = l + r >> 1;
    	if (pos <= m) insert(ls[rt], ls[last], pos, val, l, m);
    	if (m <  pos) insert(rs[rt], rs[last], pos, val, m + 1, r);
    	tag[rt] = tag[ls[rt]] + tag[rs[rt]];
    }
    long long query(int rt, int L, int R, int l, int r)
    {
    	if (L <= l && r <= R)
    	{
    		return tag[rt];
    	}
    	long long res = 0;
    	int m = l + r >> 1;
    	if (L <= m) res += query(ls[rt], L, R, l, m);
    	if (m <  R) res += query(rs[rt], L, R, m + 1, r);
    	return res;
    }
    void init()
    {
    	read(n); read(m);
    	for (int i = 1; i <= m; ++i) 
    	{
    		read(eg[i].u); read(eg[i].v); read(eg[i].w);
    		p[i] = eg[i].w;
    	}
    	sort(p + 1, p + m + 1);
    	tot = unique(p + 1, p + m + 1) - p - 1;
    	for (int i = 1; i <= m; ++i)
    		eg[i].w = lower_bound(p + 1, p + tot + 1, eg[i].w) - p;
    }
    void clear()
    {
    	for (int i = 1; i <= num; ++i) root[i] = 0;
    	for (int i = 1; i <= tot + 5; ++i) rtId[i] = 0;
    	for (int i = 1; i <= n + m; ++i)
    	{
    		fa[i] = c[i][0] = c[i][1] = val[i] = mx[i] = rev[i] = 0;
    	}
    	num = total = 0;
    }
    void work()
    {
    	build(root[0], 1, tot);
    	sort(eg + 1, eg + m + 1);
    	for (int i = 1; i <= m; ++i)
    	{
    		int u = eg[i].u, v = eg[i].v, w = eg[i].w;
    		if (find(u) == find(v))
    		{
    			int t = query(u, v);
    			cut(t, eg[t - n].u);
    			cut(t, eg[t - n].v);
    			rtId[w] = ++num;
    			insert(root[num], root[num - 1], val[t], -p[val[t]], 1, tot);	
    		}
    		val[i + n] = w; mx[i + n] = i + n;
    		link(i + n, u);
    		link(i + n, v);
    		rtId[w] = ++num;
    		insert(root[num], root[num - 1], w, p[w], 1, tot);
    	}
    }
    void solve()
    {		
    	read(q);
    	int ans = 0;
    	for (int i = 1; i <= q; ++i)
    	{
    		int u, v; 
    		read(u); read(v);
    		u -= ans; v -= ans;
    		int l = lower_bound(p + 1, p + tot + 1, u) - p;
    		int r = upper_bound(p + 1, p + tot + 1, v) - p - 1;	
    		if (r == tot + 1) r = tot;	
    		ans = query(root[rtId[l]], l, r, 1, tot);
    		cout << ans << endl;
    	}
    }
    int main()
    {	
    	int T; read(T);
    	for (int cas = 1; cas <= T; ++cas)
    	{
    		init();
    		clear();
    		work();
    		solve();
    	}
    }
    
    
  • 相关阅读:
    docker生产——容器通信
    .net core集成JWT(基础)
    JWT基本概念
    MySQL数据更新
    MySQL查询练习2
    C语言程序设计之字符串处理
    MySQL查询练习
    博客文章搬迁
    C语言程序设计之 数组2020-10-28
    Java方法重载浅谈
  • 原文地址:https://www.cnblogs.com/rpSebastian/p/7442092.html
Copyright © 2011-2022 走看看