[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();
    }
}

原文地址:https://www.cnblogs.com/mollnn/p/12382708.html