luogu3707 相关分析 (线段树)
把式子展开以后会发现,可以用线段树维护$x,y,x*y,x^2$分别的区间和
然后操作有区间加和区间修改
这个pushdown的时候,如果改和加的标记同时存在,那一定是先改再加,要不然加的标记已经被清掉了
所以在pushdown的时候,如果有改的标记,要把孩子的加的标记清掉
然后注意细节就行了(用*传数组 然后在函数里改了的话 它真的会改的 怎么就意识不到呢...)
1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4 using namespace std; 5 typedef long long ll; 6 const int maxn=1e5+10,inf=1e9; 7 8 inline ll rd(){ 9 ll x=0;char c=getchar();int neg=1; 10 while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();} 11 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 12 return x*neg; 13 } 14 15 struct Node{ 16 double x,y,xy,x2; 17 int l,r; 18 Node(double a=0,double b=0,double c=0,double d=0,int e=0,int f=0){ 19 x=a,y=b,xy=c,x2=d,l=e,r=f; 20 } 21 }tr[maxn*4]; 22 double laz[maxn*4][4]; 23 int ch[maxn*4][2],pct,X[maxn],Y[maxn]; 24 int N,M; 25 26 Node operator + (Node a,Node b){ 27 Node p; 28 p.l=a.l,p.r=b.r; 29 p.x=a.x+b.x,p.y=a.y+b.y; 30 p.xy=a.xy+b.xy,p.x2=a.x2+b.x2; 31 return p; 32 } 33 34 inline void deal(Node &p,double *v){ 35 int r=p.r,l=p.l; 36 if(v[2]!=-inf){ 37 p.x=p.y=1ll*(p.r+p.l)*(p.r-p.l+1)/2; 38 p.xy=p.x2=(1ll*r*(r+1)*(2*r+1))/6-(1ll*(l-1)*l*(2*l-1))/6; 39 v[0]+=v[2],v[1]+=v[3]; 40 } 41 42 p.x2+=(p.r-p.l+1)*v[0]*v[0]+2*v[0]*p.x; 43 p.xy+=v[0]*p.y+v[1]*p.x+(p.r-p.l+1)*v[0]*v[1]; 44 p.x+=(p.r-p.l+1)*v[0],p.y+=(p.r-p.l+1)*v[1]; 45 if(v[2]!=-inf) v[0]-=v[2],v[1]-=v[3]; 46 } 47 48 inline void pushdown(int p){ 49 // return; 50 if(!ch[p][0]) return; 51 if(laz[p][0]==0&&laz[p][1]==0&&laz[p][2]==-inf) return; 52 int a=ch[p][0],b=ch[p][1]; 53 if(laz[p][2]!=-inf){ 54 laz[a][0]=laz[a][1]=laz[b][0]=laz[b][1]=0; 55 laz[a][2]=laz[p][2],laz[a][3]=laz[p][3]; 56 laz[b][2]=laz[p][2],laz[b][3]=laz[p][3]; 57 } 58 laz[a][0]+=laz[p][0],laz[a][1]+=laz[p][1]; 59 laz[b][0]+=laz[p][0],laz[b][1]+=laz[p][1]; 60 61 deal(tr[a],laz[p]); 62 deal(tr[b],laz[p]); 63 laz[p][0]=laz[p][1]=0,laz[p][2]=laz[p][3]=-inf; 64 } 65 66 void build(int &p,int l,int r){ 67 p=++pct; 68 laz[p][2]=laz[p][3]=-inf; 69 if(l==r){ 70 tr[p]=Node(X[l],Y[l],1ll*X[l]*Y[l],1ll*X[l]*X[l],l,r); 71 }else{ 72 int m=l+r>>1; 73 build(ch[p][0],l,m); 74 build(ch[p][1],m+1,r); 75 tr[p]=tr[ch[p][0]]+tr[ch[p][1]]; 76 } 77 } 78 79 void query(int p,int l,int r,int x,int y,Node &q){ 80 pushdown(p); 81 if(x<=l&&r<=y){ 82 if(!q.l) q=tr[p]; 83 else q=q+tr[p]; 84 }else{ 85 int m=l+r>>1; 86 if(x<=m) query(ch[p][0],l,m,x,y,q); 87 if(y>=m+1) query(ch[p][1],m+1,r,x,y,q); 88 } 89 } 90 91 void add(int p,int l,int r,int x,int y,int s,int t){ 92 pushdown(p); 93 if(x<=l&&r<=y){ 94 double v[5]; 95 v[0]=s,v[1]=t;v[2]=v[3]=-inf; 96 deal(tr[p],v); 97 laz[p][0]+=s,laz[p][1]+=t; 98 pushdown(p); 99 }else{ 100 int m=l+r>>1; 101 if(x<=m) add(ch[p][0],l,m,x,y,s,t); 102 if(y>=m+1) add(ch[p][1],m+1,r,x,y,s,t); 103 tr[p]=tr[ch[p][0]]+tr[ch[p][1]]; 104 } 105 } 106 107 void change(int p,int l,int r,int x,int y,int s,int t){ 108 if(x<=l&&r<=y){ 109 double v[5]; 110 v[0]=v[1]=0,v[2]=s,v[3]=t; 111 deal(tr[p],v); 112 laz[p][0]=laz[p][1]=0,laz[p][2]=s,laz[p][3]=t; 113 pushdown(p); 114 }else{ 115 pushdown(p); 116 int m=l+r>>1; 117 if(x<=m) change(ch[p][0],l,m,x,y,s,t); 118 if(y>=m+1) change(ch[p][1],m+1,r,x,y,s,t); 119 tr[p]=tr[ch[p][0]]+tr[ch[p][1]]; 120 } 121 } 122 123 int main(){ 124 int i,j,k; 125 N=rd(),M=rd(); 126 for(i=1;i<=N;i++) X[i]=rd(); 127 for(i=1;i<=N;i++) Y[i]=rd(); 128 build(i,1,N); 129 for(i=1;i<=M;i++){ 130 int a=rd(),b=rd(),c=rd(); 131 if(a==1){ 132 Node p; 133 query(1,1,N,b,c,p); 134 double xb=p.x/(c-b+1),yb=p.y/(c-b+1); 135 double ans=0; 136 ans=p.xy-xb*p.y-yb*p.x+xb*yb*(c-b+1); 137 ans/=p.x2-2*xb*p.x+xb*xb*(c-b+1); 138 printf("%.10lf\n",ans); 139 }else{ 140 int d=rd(),e=rd(); 141 if(a==2){ 142 add(1,1,N,b,c,d,e); 143 }else if(a==3){ 144 change(1,1,N,b,c,d,e); 145 } 146 } 147 } 148 return 0; 149 }