zoukankan      html  css  js  c++  java
  • Bzoj3786: 星系探索——Splay

    题面

       Bzoj3786

    解析

       上课讲稿上的例题

      这道题是套路题,是括号序的应用,进入节点时打上$+1$标记, 退出时打上$-1$标记,这个是作为点权的系数
      先看操作2, 需要更改父节点,就是把一段区间提取出来,插入另一个地方,显然可以用Splay维护,先提取区间,再把新父亲的$+1$点旋转至根,把区间挂在根的后继的左儿子上,再把这个节点旋转至根,以更新信息

      对于操作1,求点到根的路径和,就是求括号序列的前缀和,该点对应的$+1$点或$-1$点的前缀和都可,我是把$-1$的点旋转至根,答案就是根的左儿子的子树和,因此需要维护子树和

      最后还有操作3,显然打标记,问题在对于子树和的改变, 记该子树中$+1$标记有$cnt1$个,$-1$标记有$cnt_1$个,则子树和需要加$(cnt1 - cnt_1) * delta$,因此需要维护子树中$+1$与$-1$的个数

     代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    using namespace std;
    typedef long long ll;
    const int maxn = 100004;
    
    template<class T> void read(T &re)
    {
        re=0;
        T sign=1;
        char tmp;
        while((tmp=getchar())&&(tmp<'0'||tmp>'9')) if(tmp=='-') sign=-1;
        re=tmp-'0';
        while((tmp=getchar())&&(tmp>='0'&&tmp<='9')) re=(re<<3)+(re<<1)+(tmp-'0');
        re*=sign;
    }
    
    int n, m, root, cnt, a[maxn], fir[maxn], sec[maxn];
    vector<int> G[maxn];
    
    struct spaly_tree{
        int s[2], fa, val, add, cnt1, cnt_1, fl[2];
        ll sum;
    }tr[maxn<<1];
    
    void dfs(int x)
    {
        fir[x] = ++cnt;
        tr[cnt].fl[1] = 1;
        tr[cnt].val = a[x];
        tr[cnt].sum = (ll)a[x];
        for(unsigned int i = 0; i < G[x].size(); ++i)
        {
            int id = G[x][i];
            dfs(id);
        }
        sec[x] = ++cnt;
        tr[cnt].fl[0] = 1;
        tr[cnt].val = -a[x];
        tr[cnt].sum = (ll)(-a[x]);
    }
    
    void build(int l, int r, int ff)
    {
        int mid = (l + r)>>1;
        if(l < mid)
            build(l, mid - 1, mid);
        if(mid < r)
            build(mid + 1, r, mid);
        if(ff)
            tr[ff].s[ff < mid] = mid;
        int ls = tr[mid].s[0], rs = tr[mid].s[1];
        tr[mid].fa = ff;
        tr[mid].cnt1 = tr[ls].cnt1 + tr[rs].cnt1 + tr[mid].fl[1];
        tr[mid].cnt_1 = tr[ls].cnt_1 + tr[rs].cnt_1 + tr[mid].fl[0];
        tr[mid].sum += tr[ls].sum + tr[rs].sum;
    }
    
    void spread(int x)
    {
        if(tr[x].add)
        {
            int ls = tr[x].s[0], rs = tr[x].s[1];
            if(ls)
            {
                tr[ls].sum += 1LL * (tr[ls].cnt1 - tr[ls].cnt_1) * tr[x].add;
                tr[ls].val += (tr[ls].fl[1]? tr[x].add: -tr[x].add);
                tr[ls].add += tr[x].add;
            }
            if(rs)
            {
                tr[rs].sum += 1LL * (tr[rs].cnt1 - tr[rs].cnt_1) * tr[x].add;
                tr[rs].val += (tr[rs].fl[1]? tr[x].add: -tr[x].add);
                tr[rs].add += tr[x].add;
            }
            tr[x].add = 0;
        }
    }
    
    void update(int x)
    {
        int ls = tr[x].s[0], rs = tr[x].s[1];
        tr[x].sum = tr[ls].sum + tr[rs].sum + 1LL * tr[x].val;
        tr[x].cnt1 = tr[ls].cnt1 + tr[rs].cnt1 + tr[x].fl[1];
        tr[x].cnt_1 = tr[ls].cnt_1 + tr[rs].cnt_1 + tr[x].fl[0];
    }
    
    void Rotate(int x)
    {
        int y = tr[x].fa, z = tr[y].fa, k = (tr[y].s[1] == x), w = (tr[z].s[1] == y), son = tr[x].s[k^1];
        spread(y);spread(x);
        tr[y].s[k] = son;tr[son].fa = y;
        tr[x].s[k^1] = y;tr[y].fa = x;
        tr[z].s[w] = x;tr[x].fa = z;
        update(y);update(x);
    }
    
    void Splay(int x, int to)
    {
        int y, z;
        while(tr[x].fa != to)
        {
            y = tr[x].fa;
            z = tr[y].fa;
            if(z != to)
                Rotate((tr[y].s[0] == x) ^ (tr[z].s[0] == y)? x: y);
            Rotate(x);
        }
        if(!to)
            root = x;
    }
    
    int Findpre()
    {
        spread(root);
        int now = tr[root].s[0];
        while(tr[now].s[1])
        {
            spread(now);
            now = tr[now].s[1];
        }
        spread(now);
        return now;
    }
    
    int Findnxt()
    {
        spread(root);
        int now = tr[root].s[1];
        while(tr[now].s[0])
        {
            spread(now);
            now = tr[now].s[0];
        }
        spread(now);
        return now;
    }
    
    void Remove(int x, int y)
    {
        Splay(fir[x], 0);
        int pre = Findpre();
        Splay(sec[x], 0);
        int nxt = Findnxt();
        Splay(pre, 0);
        Splay(nxt, pre);
        int now = tr[nxt].s[0];
        tr[nxt].s[0] = 0;
        update(nxt);update(pre);
        Splay(fir[y], 0);
        nxt = Findnxt();
        tr[now].fa = nxt;
        tr[nxt].s[0] = now;
        Splay(now, 0);
    }
    
    int main()
    {
        read(n);
        for(int i = 1; i < n; ++i)
        {
            int x;
            read(x);
            G[x].push_back(i+1);
        }
        for(int i = 1; i <= n; ++i)
            read(a[i]);
        cnt = 1;
        dfs(1);
        cnt ++;
        build(1, cnt, 0);
        tr[0].s[1] = root = (1 + cnt)>>1;
        read(m);
        for(int i = 1; i <= m; ++i)
        {
            char opt[3];
            scanf("%s", opt);
            if(opt[0] == 'Q')
            {
                int x;
                read(x);
                Splay(sec[x], 0);
                printf("%lld
    ", tr[tr[root].s[0]].sum);
            }
            else if(opt[0] == 'C')
            {
                int x, y;
                read(x);read(y);
                Remove(x, y);
            }
            else
            {
                int x, y;
                read(x);read(y);
                if(!y)    continue;
                Splay(fir[x], 0);
                int pre = Findpre();
                Splay(sec[x], 0);
                int nxt = Findnxt();
                Splay(pre, 0);
                Splay(nxt, pre);
                int p = tr[nxt].s[0];
                tr[p].sum += 1LL * (tr[p].cnt1 - tr[p].cnt_1) * y;
                tr[p].val += (tr[p].fl[1]? y: -y);
                tr[p].add += y;
                update(nxt);update(pre);
            }
        }
        return 0;
    }
    View Code

      

  • 相关阅读:
    LCD1602的第一个显示程序
    我的8*8点阵led做螺旋流水灯
    RS232电平TTL电平转换器MAX232相关
    如何自定义silverlight的加载页面
    关于一个页面中多个silverlight应用程序通信的总结
    ComboBox小技巧
    学习和分享的人
    转: 高效时间管理-介绍GTD
    转载:PHPexcel学习笔记2
    转载:PHPexcel学习笔记
  • 原文地址:https://www.cnblogs.com/Joker-Yza/p/11366884.html
Copyright © 2011-2022 走看看