bzoj2843极地旅行社题解

来源:互联网 发布:上海淘宝打包招聘信息 编辑:程序博客网 时间:2024/06/08 11:05
  • 题目大意
    有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 30005using 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\n", c);        }    }    for(int i = 1; i <= n; ++i)    {        delete T[i];        T[i] = NULL;    }    delete nil;    nil = NULL;    return 0;}
0 0