bzoj2959

lct+并查集

联赛之后忘了很多东西 复习一下

这并不是一棵树,所以我们不能直接上lct

但是把双联通分量缩了以后就是一棵树了

怎么缩呢 就是把splay拆了合并到一个点上

连通性和双联通分量拿两个并查集维护

access的时候x=find(fa[x])

#include<bits/stdc++.h>
using namespace std;
const int N = 1.5e5 + 5;
struct ufs {
    int fa[N];
    ufs() { for(int i = 1; i < N; ++i) fa[i] = i; }
    int find(int x) 
    { 
        return x == fa[x] ? x : fa[x] = find(fa[x]);
    }
    void link(int u, int v) 
    {
        fa[find(u)] = find(v);
    }
    bool con(int u, int v) 
    {
        return find(u) == find(v); 
    }
} a, b;
int n, m;
int val[N];
queue<int> q;
namespace lct 
{
    struct node {
        int rev, sum, w, f;
        int ch[2];
    } t[N];
    bool isr(int x) { return !t[x].f || (x != t[t[x].f].ch[0] && x != t[t[x].f].ch[1]); }
    int wh(int x) { return x == t[t[x].f].ch[1]; }
    void paint(int x)
    {
        t[x].rev ^= 1;
        swap(t[x].ch[0], t[x].ch[1]);
    }
    void upd(int x) 
    {
        t[x].sum = t[t[x].ch[0]].sum + t[t[x].ch[1]].sum + t[x].w;
    }
    void pd(int x) 
    {
        if(!t[x].rev) return;
        paint(t[x].ch[0]);
        paint(t[x].ch[1]);
        t[x].rev ^= 1;
    }
    void rotate(int x) 
    {
        int y = t[x].f, z = t[y].f, w = wh(x);
        if(!isr(y)) t[z].ch[wh(y)] = x;
        t[x].f = z;
        t[y].ch[w] = t[x].ch[w ^ 1];
        t[t[x].ch[w ^ 1]].f = y;
        t[x].ch[w ^ 1] = y;
        t[y].f = x;
        upd(y);
        upd(x);
    }
    void ptd(int x) 
    {
        if(!isr(x)) ptd(t[x].f); 
        pd(x);
    }
    void splay(int x) 
    {
        ptd(x);
        for(; !isr(x); rotate(x)) 
            if(!isr(t[x].f)) rotate(wh(x) == wh(t[x].f) ? t[x].f : x);
    }
    void access(int x) 
    {
        for(int p = 0; x; p = x, x = b.find(t[x].f)) 
        {
            splay(x);
            t[x].ch[1] = p;
            t[p].f = x; 
            upd(x);                 
        }
    }
    void rever(int x) 
    {
        access(x);
        splay(x);
        paint(x);
    }
    void expose(int x, int y)
    {
        rever(y);
        access(x);
        splay(x);
    }
    void link(int u, int v) 
    {
        rever(u);
        t[u].f = v; 
    }
    void rebuild(int x, int y) 
    {
        int rt = x;
        q.push(x);
        expose(x, y);
        while(!q.empty()) 
        {
            x = q.front();
            b.link(x, rt);
            q.pop();
            if(t[x].ch[0]) q.push(t[x].ch[0]);
            if(t[x].ch[1]) q.push(t[x].ch[1]);
            t[x].ch[0] = t[x].ch[1] = 0;
        }
        t[rt].w = t[rt].sum;
    }
} 
void link(int u, int v) 
{
    u = b.find(u);
    v = b.find(v);
    if(u == v) return;
    if(!a.con(u, v)) lct::link(u, v), a.link(u, v);
    else lct::rebuild(u, v);
}
int query(int u, int v) 
{
    u = b.find(u);
    v = b.find(v);
    if(!a.con(u, v)) return -1;
    if(u == v) return lct::t[u].w;
    lct::expose(u, v);
    return lct::t[u].sum;
}
void add(int x, int v) 
{
    x = b.find(x);
    lct::t[x].w += v;
    lct::t[x].sum += v;
    lct::splay(x);
}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) scanf("%d", &lct::t[i].w), val[i] = lct::t[i].sum = lct::t[i].w;
    while(m--)
    {
        int opt, u, v;
        scanf("%d%d%d", &opt, &u, &v);
        if(opt == 1) link(u, v);
        if(opt == 2) add(u, v - val[u]), val[u] = v;
        if(opt == 3) printf("%d\n", query(u, v));
    }
    return 0;
}
View Code

 

posted @ 2018-01-05 20:55  19992147  阅读(109)  评论(0编辑  收藏  举报