zoukankan      html  css  js  c++  java
  • bzoj3091 城市旅行

    题目描述

    题解:

    这是一道LCT+期望。

    先来看看这道题让求的E是啥。

    我们可以发现,将树链压成序列后,第i项对总和产生的贡献为$i*(n-i+1)*ai$。

    我们要维护这个东西。

    考虑合并两个区间,那么先有$as[x]=as[ls]+as[rs]$;

    然后考虑中间那个点,有$as[x]+=a[x]*(siz[ls]+1)*(siz[rs]+1)$;

    然后考虑两边影响。

    由于单点影响为$i*(n-i+1)*ai$,那么对于前边序列来说,$(n-i+1)$这一项增加了$siz[rs]+1$,

    对于后边序列来说,$i$这一项增加了$siz[ls]+1$,

    因此我们需要记录$sigma i*ai$,以及$sigma (n-i+1)*ai$,还有$sigma ai$。

    转移很简单。

    操作1,2为cut,link;

    操作3为树链加。打个标记扔到转移里即可。

    操作4询问,取出这一段树链的$as$作分子。

    分母为$siz*(siz+1)*(siz+2)/6$,比较好推。(就是写出一个式子然后把sigma打开)

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 50050
    #define ll long long
    inline int rd()
    {
        int f=1,c=0;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();}
        return f*c;
    }
    int n,m;
    ll a[N];
    struct LCT
    {
        int fa[N],ch[N][2];
        ll siz[N],a1[N],a2[N],a3[N],as[N],tag[N];
        bool res[N];
        void reser(int x)
        {
            if(!x)return ;
            res[x]^=1;
            swap(ch[x][0],ch[x][1]);
            swap(a1[x],a2[x]);
        }
        ll sz(int x)
        {
            return siz[x]*(siz[x]+1)/2*(siz[x]+2)/3;
        }
        ll Cm(int x)
        {
            return siz[x]*(siz[x]+1)/2;
        }
        void add(int x,ll d)
        {
            if(!x)return ;
            tag[x]+= d;
            a[x]  += d;
            a1[x] += Cm(x)*d;
            a2[x] += Cm(x)*d;
            a3[x] += siz[x]*d;
            as[x] += sz(x)*d;
        }
        bool isroot(int x)
        {
            return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
        }
        void update(int x)
        {
            int ls = ch[x][0],rs = ch[x][1];
            siz[x] = siz[ls]+siz[rs]+1;
            a1[x] = a1[ls] + a1[rs] + (a[x]+a3[rs])*(siz[ls]+1);
            a2[x] = a2[rs] + a2[ls] + (a[x]+a3[ls])*(siz[rs]+1);
            a3[x] = a3[ls] + a3[rs] + a[x];
            as[x] = as[ls] + as[rs] + a1[ls]*(siz[rs]+1) + a2[rs]*(siz[ls]+1) + a[x]*(siz[ls]+1)*(siz[rs]+1);
        }
        void pushdown(int x)
        {
            if(res[x])
            {
                reser(ch[x][0]);
                reser(ch[x][1]);
                res[x]=0;
            }
            if(tag[x])
            {
                add(ch[x][0],tag[x]);
                add(ch[x][1],tag[x]);
                tag[x]=0;
            }
        }
        int st[N],tl;
        void down(int x)
        {
            st[tl=1]=x;
            while(!isroot(x))x=fa[x],st[++tl]=x;
            while(tl)pushdown(st[tl]),tl--;
        }
        void rotate(int x)
        {
            int y = fa[x],z = fa[y],k = (ch[y][1]==x);
            if(!isroot(y))ch[z][ch[z][1]==y]=x;
            fa[x]=z;
            ch[y][k] = ch[x][!k],fa[ch[x][!k]] = y;
            ch[x][!k] = y,fa[y] = x;
            update(y),update(x);
        }
        void splay(int x)
        {
            down(x);
            while(!isroot(x))
            {
                int y = fa[x],z = fa[y];
                if(!isroot(y))
                    (ch[y][1]==x)^(ch[z][1]==y)?rotate(x):rotate(y);
                rotate(x);
            }
        }
        void access(int x)
        {
            int y = 0;
            while(x)
            {
                splay(x);
                ch[x][1]=y;
                update(x);
                y = x,x = fa[x];
            }
        }
        void mtr(int x)
        {
            access(x);
            splay(x);
            reser(x);
        }
        int findrt(int x)
        {
            access(x);
            splay(x);
            while(ch[x][0])x=ch[x][0];
            splay(x);
            return x;
        }
        void link(int x,int y)
        {
            mtr(x);
            fa[x]=y;
        }
        void cut(int x,int y)
        {
            mtr(x);
            access(y);
            splay(y);
            if(ch[y][0]==x)
            {
                ch[y][0]=fa[x]=0;
                update(y);
            }
        }
        void Add(int x,int y,ll d)
        {
            mtr(x);
            access(y);
            splay(y);
            add(y,d);
        }
        void init()
        {
            for(int i=1;i<=n;i++)
            {
                siz[i] = 1;
                a1[i] = a2[i] = a3[i] = as[i] = a[i];
            }
        }
    }tr;
    ll gcd(ll x,ll y)
    {
        return y?gcd(y,x%y):x;
    }
    int main()
    {
        n = rd(),m = rd();
        for(int i=1;i<=n;i++)
            a[i] = rd();
        tr.init();
        for(int f,t,i=1;i<n;i++)
        {
            f = rd(),t = rd();
            tr.link(f,t);
        }
        int opt,x,y;ll d;
        for(int i=1;i<=m;i++)
        {
            opt = rd();
            x = rd(),y = rd();
            if(opt==1)
            {
                tr.cut(x,y);
            }else if(opt==2)
            {
                if(tr.findrt(x)!=tr.findrt(y))
                {
                    tr.link(x,y);
                }
            }else if(opt==3)
            {
                d = rd();
                if(tr.findrt(x)==tr.findrt(y))tr.Add(x,y,d);
            }else
            {
                if(tr.findrt(x)==tr.findrt(y))
                {
                    tr.mtr(x);
                    tr.access(y);
                    tr.splay(y);
                    ll zi = tr.as[y];
                    ll mu = tr.Cm(y);
                    ll Gcd = gcd(zi,mu);
                    printf("%lld/%lld
    ",zi/Gcd,mu/Gcd);
                }else
                {
                    puts("-1");
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    c++11 内存模型解读
    无锁队列的实现
    c++中的原子操作
    还是说Memory Model,gcc的__sync_synchronize真是太坑爹了
    对于Linux平台下C语言开发中__sync_函数的认识
    理解 Memory barrier
    pthread_barrier_init,pthread_barrier_wait简介
    explicit构造函数的作用
    droofs
    27.
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10168997.html
Copyright © 2011-2022 走看看