Processing math: 100%

P2221 [HAOI2012]高速公路(线段树)

P2221 [HAOI2012]高速公路

显然答案为 ri=lrj=ldis[i][j]C2rl+1

下面倒是挺好算,组合数瞎搞

上面咋算呢

先考虑每条边被算上的次数ans=ri=la[i](ri+1)(il+1)

我们把它拆开再合并瞎搞,按变量i的次数分项

蓝后化出来这个式子:

ans=(rlrl+1)S1+(l+r)S2S3

S1=ri=la[i]

S2=ri=la[i]i

S3=ri=la[i]ii

显然这是可以用线段树维护的辣

区间添加k

显然S1+=(rl+1)k

S2+=ik

S3+=iik

再开俩数组维护下S4=iS5=ii就好辣

注意我们是按边开线段树,所以r=1,组合数也要改为C2rl+1

复制代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
void read(int &x){
    char c=getchar();x=0; int f=1;
    while(c<'0'||c>'9') f=f&&(c!='-'),c=getchar();
    while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar();
    x=f?x:-x;
}
#define W 400005
int n,m; ll S1,S2,S3,ans,tot,g;
ll add[W],s1[W],s2[W],s3[W],s4[W],s5[W];
#define lc o<<1
#define rc o<<1|1
#define mid (l+r)/2
inline void up(int o){
    s1[o]=s1[lc]+s1[rc],
    s2[o]=s2[lc]+s2[rc],
    s3[o]=s3[lc]+s3[rc];
}
void down(int o,int l,int r){
    if(!add[o]) return ;
    s1[lc]+=1ll*(mid-l+1)*add[o], s1[rc]+=1ll*(r-mid)*add[o];
    s2[lc]+=s4[lc]*add[o], s2[rc]+=s4[rc]*add[o];
    s3[lc]+=s5[lc]*add[o], s3[rc]+=s5[rc]*add[o];
    add[lc]+=add[o], add[rc]+=add[o]; add[o]=0;
}
void build(int o,int l,int r){
    if(l==r){s4[o]=l,s5[o]=1ll*l*l;    return ;}
    build(lc,l,mid); build(rc,mid+1,r);
    s4[o]=s4[lc]+s4[rc], s5[o]=s5[lc]+s5[rc];
}
void Add(int o,int l,int r,int x1,int x2,int v){
    if(x1<=l&&r<=x2){
        add[o]+=v, s1[o]+=(r-l+1)*v,
        s2[o]+=s4[o]*v, s3[o]+=s5[o]*v;
        return ;
    }down(o,l,r);
    if(x1<=mid) Add(lc,l,mid,x1,x2,v);
    if(x2>mid) Add(rc,mid+1,r,x1,x2,v);
    up(o);
}
void Ask(int o,int l,int r,int x1,int x2){
    if(x1<=l&&r<=x2){
        S1+=s1[o], S2+=s2[o], S3+=s3[o];
        return ;
    }down(o,l,r);
    if(x1<=mid) Ask(lc,l,mid,x1,x2);
    if(x2>mid) Ask(rc,mid+1,r,x1,x2);
}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
int main(){
    char opt[3]; int l,r,v;
    read(n);read(m); --n;
    build(1,1,n);
    while(m--){
        scanf("%s",opt); read(l);read(r); --r;
        if(opt[0]=='C') read(v),Add(1,1,n,l,r,v);
        else{
            S1=S2=S3=0; Ask(1,1,n,l,r);
            ans=1ll*(r-l-1ll*l*r+1)*S1+1ll*(l+r)*S2-S3;
            tot=1ll*(r-l+2)*(r-l+1)/2;
            g=gcd(ans,tot); ans/=g; tot/=g;
            printf("%lld/%lld\n",ans,tot);
        }
    }return 0;
}
复制代码

 

posted @   kafuuchino  阅读(292)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示