题面
https://www.lydsy.com/JudgeOnline/problem.php?id=4821
题解
做法显然 就是维护一颗线段树
里面装4个东西 区间x的和 区间y的和 区间$x^2$的和 区间$xy$的和
然后装4个标记 add操作对x的影响 add操作对y的影响 cover操作对x的影响 cover操作对y的影响
唯一要想一想的东西在于怎么维护顺序
我一开始的愚蠢做法是每个节点维护一个nw nw=0表示当前节点上一次受到的操作是add nw=1表示....是cover
然后每次pushdown的时候 例如当前节点的nw是0 现在我们把它pushdown 我们看左儿子 如果他的nw是1 我们就得先pushdown它的左儿子 然后在更新左儿子的值 右儿子类似
如果当前节点的nw是1 也就是cover操作 就不需要管左儿子和右儿子的nw 因为全都被cover掉了
这样复杂度是
事实上这样写很麻烦
我们不需要维护nw 因为cover操作的特殊性: cover之后就不用管之前干了什么
那么对于一个节点 如果tag1,tag2不为0 且tag3,tag4也不为0 那么我们先做tag3,tag4也就是先cover
每次cover操作的时候我们把节点的tag1,tag2设为0,也就是之前的操作全不管
这样复杂度少一个log 而且好写一些
Code
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 ll read(){ 6 ll x=0,f=1;char c=getchar(); 7 while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();} 8 while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();} 9 return x*f; 10 } 11 12 struct Node{ 13 int l,r; 14 long double x,y,xy,x2; 15 long double tag1,tag2,tag3,tag4; 16 //如果tag1,tag3同时有值,表示先算cover操作(tag3,tag4)再算add操作(tag1,tag2) 17 Node(){ 18 x=y=xy=x2=0; 19 } 20 21 void pr(){ 22 cout<<x<<' '<<y<<' '<<xy<<' '<<x2<<endl; 23 } 24 } tr[400400]; 25 26 #define lc (i<<1) 27 #define rc (i<<1|1) 28 ll x[100100],y[100100]; 29 30 inline long double calc_sum(int l,int r){ 31 return (long double)(r-l+1)*(l+r)/2; 32 } 33 inline long double calc_sqr(int l){ 34 return (long double)l*(l+1)*(2*l+1)/6; 35 } 36 inline long double calc_sqr(int l,int r){ 37 return calc_sqr(r)-calc_sqr(l-1); 38 } 39 40 void update(int i){ 41 tr[i].x=tr[lc].x+tr[rc].x; 42 tr[i].y=tr[lc].y+tr[rc].y; 43 tr[i].xy=tr[lc].xy+tr[rc].xy; 44 tr[i].x2=tr[lc].x2+tr[rc].x2; 45 } 46 47 void build(int i,int l,int r){ 48 tr[i].l=l,tr[i].r=r; 49 if(l==r){ 50 tr[i].x=x[l],tr[i].y=y[l]; 51 tr[i].x2=(long double)x[l]*x[l],tr[i].xy=(long double)x[l]*y[l]; 52 return; 53 } 54 int md=(l+r)>>1; 55 build(lc,l,md),build(rc,md+1,r); 56 update(i); 57 } 58 59 void CHANGE(int i,long double s,long double t){ 60 tr[i].tag3=s,tr[i].tag4=t; 61 tr[i].tag1=tr[i].tag2=0; 62 int len=tr[i].r-tr[i].l+1; 63 tr[i].x=calc_sum(s+tr[i].l,s+tr[i].r); 64 tr[i].y=calc_sum(t+tr[i].l,t+tr[i].r); 65 tr[i].x2=calc_sqr(s+tr[i].l,s+tr[i].r); 66 tr[i].xy=s*t*len+calc_sum(tr[i].l,tr[i].r)*t+calc_sum(tr[i].l,tr[i].r)*s+calc_sqr(tr[i].l,tr[i].r); 67 } 68 69 void pushdown2(int i){ 70 long double s=tr[i].tag3,t=tr[i].tag4; 71 CHANGE(lc,s,t); 72 CHANGE(rc,s,t); 73 tr[i].tag3=tr[i].tag4=0; 74 } 75 76 void change(int i,long double s,long double t){ 77 tr[i].tag1+=s,tr[i].tag2+=t; 78 int len=tr[i].r-tr[i].l+1; 79 tr[i].x2+=2*tr[i].x*s+s*s*len; 80 tr[i].xy+=tr[i].x*t+tr[i].y*s+s*t*len; 81 tr[i].x+=s*len; 82 tr[i].y+=t*len; 83 } 84 85 void pushdown1(int i){ 86 long double s=tr[i].tag1,t=tr[i].tag2; 87 change(lc,s,t); 88 change(rc,s,t); 89 tr[i].tag1=tr[i].tag2=0; 90 } 91 92 void pushdown(int i){ 93 if(tr[i].tag3!=0 || tr[i].tag4!=0){ 94 pushdown2(i); 95 } 96 if(tr[i].tag1!=0 || tr[i].tag2!=0){ 97 pushdown1(i); 98 } 99 } 100 101 void change1(int i,int l,int r,int s,int t){ 102 if(tr[i].l>r || tr[i].r<l) return; 103 if(tr[i].l>=l && tr[i].r<=r){ 104 change(i,s,t); 105 return; 106 } 107 pushdown(i); 108 change1(lc,l,r,s,t); 109 change1(rc,l,r,s,t); 110 update(i); 111 } 112 113 void change2(int i,int l,int r,int s,int t){ 114 if(tr[i].l>r || tr[i].r<l) return; 115 if(tr[i].l>=l && tr[i].r<=r){ 116 CHANGE(i,s,t); 117 return; 118 } 119 pushdown(i); 120 change2(lc,l,r,s,t); 121 change2(rc,l,r,s,t); 122 update(i); 123 } 124 125 Node query(int i,int l,int r){ 126 Node ret; 127 if(tr[i].l>r || tr[i].r<l) return ret; 128 if(tr[i].l>=l && tr[i].r<=r) return tr[i]; 129 pushdown(i); 130 Node n1,n2; 131 n1=query(lc,l,r); 132 n2=query(rc,l,r); 133 ret.x=n1.x+n2.x;ret.y=n1.y+n2.y;ret.xy=n1.xy+n2.xy;ret.x2=n1.x2+n2.x2; 134 return ret; 135 } 136 137 void ask(int l,int r){ 138 int len=r-l+1; 139 Node nw=query(1,l,r); 140 //nw.pr(); 141 long double xba=nw.x*1.0/len,yba=nw.y*1.0/len; 142 long double fz=nw.xy-nw.y*xba-nw.x*yba+xba*yba*len; 143 long double fm=nw.x2-2*nw.x*xba+xba*xba*len; 144 printf("%.10Lf\n",fz/fm); 145 } 146 147 int n,m; 148 149 int main(){ 150 #ifdef LZT 151 freopen("in","r",stdin); 152 #endif 153 n=read(),m=read(); 154 for(int i=1;i<=n;i++) x[i]=read(); 155 for(int i=1;i<=n;i++) y[i]=read(); 156 build(1,1,n); 157 while(m--){ 158 int tp=read(); 159 if(tp==1){ 160 int l=read(),r=read(); 161 ask(l,r); 162 } 163 else if(tp==2){ 164 int l=read(),r=read(),s=read(),t=read(); 165 change1(1,l,r,s,t); 166 } 167 else if(tp==3){ 168 int l=read(),r=read(),s=read(),t=read(); 169 change2(1,l,r,s,t); 170 } 171 } 172 return 0; 173 } 174 175 /* 176 3 5 177 1 2 3 178 1 2 3 179 1 1 3 180 2 2 3 -3 2 181 1 1 2 182 3 1 2 2 1 183 1 1 3 184 */
Review
都得开long double
一开始只开了long long 爆炸 调了半天