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]區間內統計答案。ios

對於每一個詢問[L, R],要將端點離散化成對應的邊權表示,要注意離散化後的區間應被原來的區間包含,而不是包含原來的區間。c++

#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();
    }
}
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息