高速公路题解

高速公路题解

我们看一看题,就知道概率是是区间内所有线段的权值和/线段个数。
那么,我们需要动态维护区间的数据结构,
很容易想到线段树,
考虑,如何将两个区间合并:

注:以下线段树上的每个点的\(sum\)在代码中为\(sum2\),仅为方便理解。

不妨设每个区间\([l,r]\)内的所有线段权值和为\(w\)\([l,r]\)的线段权值为\(sum\),左端点为\(l\)的所有线段权值和为\(lw\),右端点为\(r\)的所有线段的权值和为\(rw\),懒标记为\(lazy\),区间长度为\(lenx=r-l+1\)
假如此区间为\(x\),左区间为\(lc\),右区间为\(rc\):
\(x\)\(w\)除去由\(lc,rc\)各自区间内部的\(w\)外,
还由经过左右两个区间的线段构成,
画图理解一下:

然后第二个问题来了,如何维护\(lw,rw\)?

至于\(sum,lazy\)还用说吗? 线段树模板啊!

xd pushup(xd u,xd v){
   xd ans; int len=u.lenx+v.lenx;
   ans.lw=u.lw+v.lw+v.lenx*u.sum2,ans.rw=u.rw+v.rw+u.lenx*v.sum2,ans.lazy=0;
   ans.w=u.w+v.w+u.lenx*v.lw+v.lenx*u.rw,ans.sum2=u.sum2+v.sum2,ans.lenx=len;
   return ans;
}

再想想下传标记:
对于每个\(x\)\(w\),所有线段都加了线段长度\(*lazy[x]\);
\(sum[len]\)为长度为\(len\)的区间所有线段的长度和。
\(l-1\)每增加一个长度,则每个长度的线段都有一个,即为:\(\sum_{i=1}^{l}=/frac{(l+1)*l}{2}\)
递推即可。

for(ll i=1;i<=n;++i) sum[i]=sum[i-1]+i*(i+1)/2;

所以:

t[lc].w+=sum[t[lc].lenx]*t[x].lazy,t[rc].w+=sum[t[rc].lenx]*t[x].lazy;

对于\(lw\)\(rw\)
区间\([l,r]\)长度在[1,r-l+1]的线段都有一种:

t[lc].lw+=(t[lc].lenx+1)*t[lc].lenx/2*t[x].lazy,t[lc].rw+=(t[lc].lenx+1)*t[lc].lenx/2*t[x].lazy;
t[rc].lw+=(t[rc].lenx+1)*t[rc].lenx/2*t[x].lazy,t[rc].rw+=(t[rc].lenx+1)*t[rc].lenx/2*t[x].lazy;

\(sum,lenx,lazy\)的下传也不讲了。

#include<bits/stdc++.h>
#define ll long long 
#define lc x<<1
#define rc x<<1|1
using namespace std;
const int N=1e5+6;
int n,m,t3;
ll sum[N],o,p,q,t1,t2;
char c[12];
struct xd{ll w,lazy,lw,rw,lenx,sum2;}t[N<<2];
inline int read(){
   int T=0,F=1; char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
   while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
   return F*T;
}
ll gcd(ll u,ll v){return u%v==0?v:gcd(v,u%v);}
void pushdown(int x){
     if(t[x].lazy){
        t[lc].lazy+=t[x].lazy,t[rc].lazy+=t[x].lazy;
        t[lc].w+=sum[t[lc].lenx]*t[x].lazy,t[rc].w+=sum[t[rc].lenx]*t[x].lazy;
        t[lc].lw+=(t[lc].lenx+1)*t[lc].lenx/2*t[x].lazy,t[lc].rw+=(t[lc].lenx+1)*t[lc].lenx/2*t[x].lazy;
        t[rc].lw+=(t[rc].lenx+1)*t[rc].lenx/2*t[x].lazy,t[rc].rw+=(t[rc].lenx+1)*t[rc].lenx/2*t[x].lazy;
        t[lc].sum2+=t[lc].lenx*t[x].lazy,t[rc].sum2+=t[rc].lenx*t[x].lazy;
        t[x].lazy=0;
     }
}
xd pushup(xd u,xd v){
   xd ans; int len=u.lenx+v.lenx;
   ans.lw=u.lw+v.lw+v.lenx*u.sum2,ans.rw=u.rw+v.rw+u.lenx*v.sum2,ans.lazy=0;
   ans.w=u.w+v.w+u.lenx*v.lw+v.lenx*u.rw,ans.sum2=u.sum2+v.sum2,ans.lenx=len;
   return ans;
}
void build(int l,int r,int x){
     t[x].lenx=r-l+1;
     if(l==r) return;
     int mid=l+r>>1;
     build(l,mid,lc),build(mid+1,r,rc);
} 
void update(ll l,ll r,int p,int q,int x,ll y){
     if(p<=l&&r<=q){t[x].lazy+=y,t[x].w+=sum[r-l+1]*y,t[x].lw+=(r-l+1)*(r-l+2)/2*y,t[x].rw+=(r-l+1)*(r-l+2)/2*y,t[x].sum2+=(r-l+1)*y;  return;}
     pushdown(x); int mid=l+r>>1;
     if(p<=mid) update(l,mid,p,q,lc,y);
     if(q>mid) update(mid+1,r,p,q,rc,y);
     t[x]=pushup(t[lc],t[rc]);
}
xd query(int l,int r,int p,int q,int x){
   if(p<=l&&r<=q){return t[x];}
   pushdown(x); int mid=l+r>>1; xd ans;
   if(q<=mid) ans=query(l,mid,p,q,lc);
   else if(p>mid) ans=query(mid+1,r,p,q,rc);
   else ans=pushup(query(l,mid,p,q,lc),query(mid+1,r,p,q,rc));
   return ans;
}
int main(){
    n=read(),m=read(),--n;
    for(ll i=1;i<=n;++i) sum[i]=sum[i-1]+i*(i+1)/2;
    build(1,n,1);
    for(int i=1;i<=m;++i){
        scanf("%s",c); t1=read(),t2=read()-1;
        if(c[0]=='C') t3=read(),update(1,n,t1,t2,1,t3);
        else{
            o=(t2-t1+1)*(t2-t1+2)/2,p=query(1,n,t1,t2,1).w;
            if(p) q=gcd(o,p),o/=q,p/=q;
            else o=1;
            printf("%lld/%lld\n",p,o);
        }
    }
    return 0;
}  

猜你喜欢

转载自www.cnblogs.com/ljk123-de-bo-ke/p/11405360.html