1. 程式人生 > >ural1855 線段樹區間更新+推公式維護一元二次式

ural1855 線段樹區間更新+推公式維護一元二次式

和威威貓系列故事差不多,都是根據條件推出公式

/*
操作c a b d:a到b道路上的所有邊權值加d
操作e a b:問a到b中包含的道路的平均權值
區間平均值=所有可能路徑權值/所有路徑數,
而路徑數=len*(len+1)/2,那麼只要求區間中所有路徑的權值即可
對於屬於路徑[L,R]的路徑[k,k+1](設為x路徑),那麼可推出有(K-L+1)(R-K)條路徑經過x路徑,則路徑x對於[L,R]的貢獻就是w[k]*(K-L+1)(R-K)
化簡得seg[k]*(-k*k+(R+L-1)*k+R*(1-L)),那麼只要維護一元二次式中k的三個係數即可

那麼[L,R]中所有路徑權值的和就是sum{seg[k] * (-k*k + (R-L+1)*k + R*(1-L)}
                            =-sum{seg[k]*k*k} + (R-L+1)sum{seg[k]*k} + R*(1-L)sum{seg[k]}
一顆線段樹add維護區間累加的值,三顆線段sum1,sum2,sum3維護三個獨立的sum,一顆二維mul線段樹維護區間k*k,k,1的值(固定的)
另外將道路離散化成點[L,R]中的每個k可以對應[L,R-1]
*/ #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; #define ll long long #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define maxn 100005 ll sum[maxn<<2],sumk[maxn<<2],sumkk[maxn<<2]; ll add[maxn<<2
],multi[maxn<<2][3]; int N,M; ll S,SK,SKK;//分別是三個係數的和 inline void pushup(int rt){ sum[rt]=sum[rt<<1]+sum[rt<<1|1]; sumk[rt]=sumk[rt<<1]+sumk[rt<<1|1]; sumkk[rt]=sumkk[rt<<1]+sumkk[rt<<1|1]; } //區間每次加上Add都要進行更新,Add對每個sum的貢獻量就是Add乘以multi inline void maintain(int
rt,ll Add){ sum[rt]+=multi[rt][0]*Add; sumk[rt]+=multi[rt][1]*Add; sumkk[rt]+=multi[rt][2]*Add; } inline void pushdown(int rt){ if(add[rt]){ add[rt<<1]+=add[rt]; add[rt<<1|1]+=add[rt]; maintain(rt<<1,add[rt]); maintain(rt<<1|1,add[rt]); add[rt]=0; } } void build(int l,int r,int rt){ if(l==r){ sum[rt]=sumk[rt]=sumkk[rt]=0; add[rt]=0; multi[rt][0]=1; multi[rt][1]=(ll)r; multi[rt][2]=(ll)r*r; return; } int m=l+r>>1; build(lson); build(rson); pushup(rt); for(int i=0;i<3;i++) multi[rt][i]=multi[rt<<1][i]+multi[rt<<1|1][i]; } void update(int L,int R,ll C,int l,int r,int rt){ if(L<=l && R>=r){ add[rt]+=C; maintain(rt,C); return; } pushdown(rt); int m=l+r>>1; if(L<=m) update(L,R,C,lson); if(R>m) update(L,R,C,rson); pushup(rt); } //查詢區間[L,R],求出區間[L,R]的三個sum分別是多少 void query(int L,int R,int l,int r,int rt){ if(L<=l && R>=r){ S+=sum[rt]; SK+=sumk[rt]; SKK+=sumkk[rt]; return; } pushdown(rt); int m=l+r>>1; if(L<=m) query(L,R,lson); if(R>m) query(L,R,rson); } int main(){ while(scanf("%d%d",&N,&M)==2){ build(1,N,1); char s[20]; for(int i=1;i<=M;i++){ scanf("%s",s); if(s[0]=='c'){ int a,b,c; scanf("%d%d%d",&a,&b,&c); update(a,b-1,(ll)c,1,N,1); } else { int a,b; scanf("%d%d",&a,&b); S=(ll)0; SK=(ll)0; SKK=(ll)0; query(a,b-1,1,N,1); double ans=-SKK+((ll)a+b-1)*SK+(ll)b*(1-a)*S; ll tot=(ll)(b-a)*(b-a+1)/2; printf("%.10f\n",ans/tot); } } } return 0; }