zoukankan      html  css  js  c++  java
  • [HAOI2012] 高速公路


    Solution

    考虑每一个询问答案的分子

    用线段树维护序列,每个节点记录以下内容

    • 本区间的长度 (len)
    • 本区间的边权和 (sum)
    • 自左向右的二阶前缀和 (vl=sum_{i} ia_i)
    • 自右向左的二阶前缀和 (vr=sum_i (len-i)a_i)
    • 本区间内的答案 (ans)
    • 本区间的加法标记 (tag)

    这样就可以对区间进行 (O(1)) 的快速合并

    考虑如何下传标记,设要放置的标记值为 (t),则

    • (sum+tlen o sum)
    • (vl+frac{len(len+1)}{2}t o vl, vr+frac{len(len+1)}{2}t o vr)
    • (ans + p_{len}t o ans),其中 (p_{i}=sum_{j=1}^i (len-i+1)i),有递推关系 (p_i=p_{i-1}+frac{i(i-1)}{2}+i),故可以预处理出
    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    const int N = 1000005;
    
    int P[N],a[N];
    
    struct node {
        int len,sum,vl,vr,ans,tag;
        void print() {
            cout<<len<<" "<<sum<<" "<<vl<<" "<<vr<<" "<<ans<<" "<<tag<<endl;
        }
    } tr[N];
    
    node merge(node l,node r) {
        node ret;
        ret.len = l.len+r.len;
        ret.sum = l.sum+r.sum;
        ret.vl = l.vl+r.vl+l.len*r.sum;
        ret.vr = r.vr+l.vr+r.len*l.sum;
        ret.ans = l.ans+r.ans+l.vl*(r.len)+r.vr*(l.len);
        ret.tag = 0;
        return ret;
    }
    
    void pushdown(int p) {
        if(tr[p].tag) {
            int t=tr[p].tag;
            tr[p*2].sum+=t*tr[p*2].len;
            tr[p*2].vl+=tr[p*2].len*(tr[p*2].len+1)/2*t;
            tr[p*2].vr+=tr[p*2].len*(tr[p*2].len+1)/2*t;
            tr[p*2].ans+=P[tr[p*2].len]*t;
            tr[p*2+1].sum+=t*tr[p*2+1].len;
            tr[p*2+1].vl+=tr[p*2+1].len*(tr[p*2+1].len+1)/2*t;
            tr[p*2+1].vr+=tr[p*2+1].len*(tr[p*2+1].len+1)/2*t;
            tr[p*2+1].ans+=P[tr[p*2+1].len]*t;
            tr[p*2].tag+=t;
            tr[p*2+1].tag+=t;
            tr[p].tag=0;
        }
    }
    
    void build(int p,int l,int r) {
        if(l==r) {
            tr[p]=node({1,a[l],a[l],a[l],a[l],0});
        }
        else {
            build(p*2,l,(l+r)/2);
            build(p*2+1,(l+r)/2+1,r);
            tr[p]=merge(tr[p*2],tr[p*2+1]);
        }
    }
    
    void modify(int p,int l,int r,int ql,int qr,int t) {
        if(l>qr || r<ql) return;
        if(l>=ql&&r<=qr) {
            tr[p].sum+=t*tr[p].len;
            tr[p].vl+=tr[p].len*(tr[p].len+1)/2*t;
            tr[p].vr+=tr[p].len*(tr[p].len+1)/2*t;
            tr[p].ans+=P[tr[p].len]*t;
            tr[p].tag+=t;
        }
        else {
            pushdown(p);
            modify(p*2,l,(l+r)/2,ql,qr,t);
            modify(p*2+1,(l+r)/2+1,r,ql,qr,t);
            tr[p]=merge(tr[p*2],tr[p*2+1]);
        }
    }
    
    node query(int p,int l,int r,int ql,int qr) {
        if(l>qr || r<ql) return node({0,0,0,0,0,0});
        if(l>=ql&&r<=qr) return tr[p];
        pushdown(p);
        return merge(query(p*2,l,(l+r)/2,ql,qr),query(p*2+1,(l+r)/2+1,r,ql,qr));
    }
    
    int n,m,t1,t2,t3;
    
    char op;
    
    signed main() {
        ios::sync_with_stdio(false);
        cin>>n>>m;
        --n;
        P[1]=1;
        for(int i=2;i<=n;i++) P[i]=P[i-1]+i*(i-1)/2+i;
        build(1,1,n);
        while(m--) {
            cin>>op;
            if(op=='C') {
                cin>>t1>>t2>>t3;
                --t2;
                modify(1,1,n,t1,t2,t3);
            }
            else {
                cin>>t1>>t2;
                --t2;
                int ans = query(1,1,n,t1,t2).ans;
                int mom = (t2-t1+1)*(t2-t1+2)/2;
                int g = __gcd(ans,mom);
                ans/=g; mom/=g;
                cout<<ans<<"/"<<mom<<endl;
            }
            //for(int i=1;i<=10;i++) tr[i].print();
        }
    }
    
    
  • 相关阅读:
    8.ps输出属性-----状态
    洛谷P1057 传球游戏
    动态规划
    洛谷P1192 台阶问题
    最大公约数和最小公倍数
    C++ memcpy()函数用法
    next_permutation(a,a+n)
    std::ios::sync_with_stdio(false);
    让计算机很快地求出a^b%c;
    洛谷P1433 吃奶酪
  • 原文地址:https://www.cnblogs.com/mollnn/p/12382708.html
Copyright © 2011-2022 走看看