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

    Description

    Input

    Output

    Sample Input

    4 5
    1 3 2 5
    1 2
    1 3
    2 4
    4 2 4
    1 2 4
    2 3 4
    3 1 4 1
    4 1 4

    Sample Output

    16/3
    6/1

    HINT

    对于所有数据满足 1<=N<=50,000 1<=M<=50,000 1<=Ai<=10^6 1<=D<=100 1<=U,V<=N

     
    恶心的动态树上维护各种信息。
    不难发现ans=ΣAi*i*(len-i+1)。
    我们在splay树上维护几个值:
    sumv=ΣAi*i*(len-i+1)
    lsum=ΣAi*i
    rsum=ΣAi*(len-i+1)
    sum=ΣAi
    不难维护者几个变量的关系,打懒标记时快速算一下Σi*(len-i+1)和Σi就行了。
    注意flip时要交换两子树的lsum和rsum。
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cctype>
    #define lc ch[x][0]
    #define rc ch[x][1]
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define ren for(int i=first[x];i!=-1;i=next[i])
    using namespace std;
    const int BufferSize=1<<16;
    char buffer[BufferSize],*head,*tail;
    inline char Getchar() {
        if(head==tail) {
            int l=fread(buffer,1,BufferSize,stdin);
            tail=(head=buffer)+l;
        }
        return *head++;
    }
    inline int read() {
        int x=0,f=1;char c=Getchar();
        for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
        return x*f;
    }
    typedef long long ll;
    const int maxn=50010;
    ll f[maxn],sumv[maxn],sum[maxn],lsum[maxn],rsum[maxn],s[maxn],addv[maxn],val[maxn];
    int pre[maxn],fa[maxn],ch[maxn][2],flip[maxn];
    void Add(int x,ll v) {
        if(!v||!x) return;
        sumv[x]+=v*f[s[x]];
        lsum[x]+=v*(1+s[x])*s[x]/2;
        rsum[x]+=v*(1+s[x])*s[x]/2;
        sum[x]+=v*s[x];
    }
    void maintain(int x) {
        if(!x) return;
        s[x]=s[lc]+s[rc]+1;
        sum[x]=sum[lc]+sum[rc]+val[x];
        sumv[x]=sumv[lc]+sumv[rc]+lsum[lc]*(s[rc]+1)+rsum[rc]*(s[lc]+1)+val[x]*(s[lc]+1)*(s[rc]+1);
        lsum[x]=lsum[lc]+lsum[rc]+val[x]*(s[lc]+1)+sum[rc]*(s[lc]+1);
        rsum[x]=rsum[rc]+rsum[lc]+val[x]*(s[rc]+1)+sum[lc]*(s[rc]+1);
        Add(x,addv[x]);
    }
    void pushdown(int x) {
        if(flip[x]) {
            swap(lc,rc);
            swap(lsum[lc],rsum[lc]);
            swap(lsum[rc],rsum[rc]);
            flip[lc]^=1;flip[rc]^=1;
            flip[x]=0;
        }
        if(addv[x]) {
            val[x]+=addv[x];addv[lc]+=addv[x];addv[rc]+=addv[x];
            Add(lc,addv[x]);Add(rc,addv[x]);addv[x]=0;
        }
    }
    void rotate(int x) {
        int y=pre[x],z=pre[y],d=ch[y][0]==x;
        ch[y][d^1]=ch[x][d];pre[ch[x][d]]=y;
        ch[z][ch[z][1]==y]=x;pre[x]=z;
        ch[x][d]=y;pre[y]=x;maintain(y);
    }
    int S[maxn],top;
    void splay(int x) {
        for(int i=x;i;i=pre[i]) S[++top]=i;
        if(top!=1) fa[x]=fa[S[top]],fa[S[top]]=0;
        while(top) pushdown(S[top--]);
        while(pre[x]) rotate(x);
        maintain(x);
    }
    void access(int x) {
        for(int y=0;x;x=fa[x]) {
            splay(x);pre[ch[x][1]]=0;fa[ch[x][1]]=x;
            ch[x][1]=y;pre[y]=x;maintain(y=x);
        }
    }
    void makeroot(int x) {
        access(x);splay(x);flip[x]^=1;
        maintain(x);
    }
    int find(int x) {
        access(x);splay(x);
        while(ch[x][0]) x=ch[x][0];
        return x;
    }
    void link(int x,int y) {
        makeroot(x);fa[x]=y;
    }
    void cut(int x,int y) {
        makeroot(x);access(y);splay(y);
        if(s[y]==2) {
            pre[ch[y][0]]=0;ch[y][0]=0;
            maintain(y);
        }
    }
    ll gcd(ll x,ll y) {return !y?x:gcd(y,x%y);}
    void query(int x,int y) {
        makeroot(x);access(y);splay(y);
        ll len=s[y]-1;len=(len+1)*(len+2)/2;
        ll ans=sumv[y],t=gcd(len,ans);
        printf("%lld/%lld
    ",ans/t,len/t);
    }
    void update(int x,int y,ll v) {
        makeroot(x);access(y);splay(y);
        addv[y]+=v;Add(y,v);
    }
    int main() {
        int n=read(),m=read();
        f[1]=1;
        rep(i,2,n) f[i]=f[i-1]+(ll)i*(i-1)/2+i; 
        rep(i,1,n) val[i]=read();
        rep(i,1,n-1) link(read(),read());
        while(m--) {
            int t=read(),x=read(),y=read();
            if(t==1) if(find(x)==find(y)) cut(x,y);
            if(t==2) if(find(x)!=find(y)) link(x,y);
            if(t==3) {
                ll v=read();
                if(find(x)==find(y)) update(x,y,v);
            }
            if(t==4) {
                if(find(x)==find(y)) query(x,y);
                else puts("-1");
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    java基础知识:私有成员变量
    分布式架构:概述一
    java基础知识:内存
    原油期货价格跌至-37美元/桶的影响
    贷款利息
    java基础知识:IntelliJ IDEA的基础设置
    正则表达式的常用方法
    http服务器三:自己写一个服务器实现转发功能
    bzoj3875: [Ahoi2014&Jsoi2014]骑士游戏(用spfa解决有后效性的dp)
    bzoj2118: 墨墨的等式(巧妙的单源最短路+priority_queue)
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5208038.html
Copyright © 2011-2022 走看看