zoukankan      html  css  js  c++  java
  • bzoj2843极地旅行社题解

    • 题目大意
      有n座小岛,当中每一个岛都有若干帝企鹅。

      一開始岛与岛之间互不相连。有m个操作。各自是在两个岛之间修一座双向桥,若两岛已连通则不修并输出no,若不连通就输出yes并修建。改动一个岛上帝企鹅的数量;询问从岛A到岛B可看到多少帝企鹅,若到不了输出impossible。

    • 题解
      继续试水LCT。LCT维护每一个点自身的企鹅数以及其在Splay下的子树的企鹅数的总和。

      修桥操作要在LCT中询问是否有同样的根,没有则添边。改动时把要被改动的点弄到树根去,直接改动就可以。查询时要先推断是否为同一结点,再推断是否连通。若连通,则把当中一个点x弄到根上,还有一个点y用access连上去,再用Splay把y弄到辅助树的根上。

      这时x一定是y最左端的子孙(由于它是根。中序序列里最靠前)。直接输出y左子树企鹅的总和加上y自己的企鹅数就可以。

    • Code

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define maxn 30005
    using namespace std;
    int n, m;
    struct node *nil, *T[maxn], *S[maxn];
    struct node
    {
        bool rev;
        int val, s;
        node *fa, *lc, *rc;
        node(bool rev = false, int val = 0, int s = 0, node *fa = nil, node *lc = nil, node *rc = nil)
            : rev(rev), val(val), s(s), fa(fa), lc(lc), rc(rc) {}
        inline void update()
        {
            s = lc -> s + rc -> s + val;
        }
        inline void rever()
        {
            rev ^= 1;
            swap(lc, rc);
        }
        inline void pushdown()
        {
            if(rev)
            {
                rev = false;
                lc -> rever(); rc -> rever();
            }
        }
    };
    inline void zig(node *x)
    {
        node *y = x -> fa;
        y -> lc = x -> rc;
        x -> rc -> fa = y;
        x -> rc = y;
        x -> fa = y -> fa;
        if(y == y -> fa -> lc) y -> fa -> lc = x;
        else if(y == y -> fa -> rc) y -> fa -> rc = x;
        y -> fa = x;
        y -> update();
    }
    inline void zag(node *x)
    {
        node *y = x -> fa;
        y -> rc = x -> lc;
        x -> lc -> fa = y;
        x -> lc = y;
        x -> fa = y -> fa;
        if(y == y -> fa -> lc) y -> fa -> lc = x;
        else if(y == y -> fa -> rc) y -> fa -> rc = x;
        y -> fa = x;
        y -> update();
    }
    void splay(node *x)
    {
        int top = 0;
        S[top++] = x;
        for(node *i = x; i == i -> fa -> lc || i == i -> fa -> rc; i = i -> fa)
        {
            S[top++] = i -> fa;
        }
        while(top--) S[top] -> pushdown();
        node *y = nil, *z = nil;
        while(x == x -> fa -> lc || x == x -> fa -> rc)
        {
            y = x -> fa; z = y -> fa;
            if(x == y -> lc)
            {
                if(y == z -> lc) zig(y);
                zig(x);
            }
            else
            {
                if(y == z -> rc) zag(y);
                zag(x);
            }
        }
        x -> update();
    }
    inline void access(node *x)
    {
        for(node *y = nil; x != nil; y = x, x = x -> fa)
        {
            splay(x);
            x -> rc = y;
            x -> update();
        }
    }
    inline void makeroot(node *x)
    {
        access(x); splay(x); x -> rever();
    }
    inline void lnk(node *x, node *y)
    {
        makeroot(x);
        x -> fa = y;
        splay(y);
    }
    inline node* find(node *x)
    {
        access(x); splay(x);
        while(x -> lc != nil) x = x -> lc;
        return x;
    }
    inline void change(node *x, int k)
    {
        makeroot(x);
        x -> val = k;
        x -> update();
    }
    inline int query(node *x, node *y)
    {
        if(x == y) return x -> val;
        if(find(x) != find(y)) return -1;
        makeroot(x);
        access(y);
        splay(y);
        return (y -> lc -> s + y -> val);
    }
    int main()
    {
        int a, b, c;
        char ch[10];
        scanf("%d", &n);
        nil = new node(); *nil = node();
        for(int i = 1; i <= n; ++i) T[i] = new node();
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d", &(T[i] -> val));
            T[i] -> update();
        }
        scanf("%d", &m);
        while(m--)
        {
            scanf("%s%d%d", ch, &a, &b);
            if(ch[0] == 'b')
            {
                if(find(T[a]) != find(T[b]))
                {
                    lnk(T[a], T[b]); puts("yes");
                }
                else puts("no");
            }
            else if(ch[0] == 'p')
            {
                change(T[a], b);
            }
            else
            {
                c = query(T[a], T[b]);
                if(c == -1) puts("impossible");
                else printf("%d
    ", c);
            }
        }
        for(int i = 1; i <= n; ++i)
        {
            delete T[i];
            T[i] = NULL;
        }
        delete nil;
        nil = NULL;
        return 0;
    }
  • 相关阅读:
    Program C--二分
    Program A-归并排序
    Program E-- CodeForces 18C
    Program B--CodeForces 492B
    2015 HUAS Provincial Select Contest #1 C
    2015 HUAS Provincial Select Contest #1 B
    2015 HUAS Provincial Select Contest #1 A
    CSU 1111.三家人。第三次选拔赛D题:整理花园酬劳分配问题
    将10进制整数转换成16进制整数输出
    -UVa10935题:Trowing cards away1解答及简单分析
  • 原文地址:https://www.cnblogs.com/mthoutai/p/7040189.html
Copyright © 2011-2022 走看看