bzoj 4821 [Sdoi2017]相关分析

题面

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

  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 */
View Code

Review

都得开long double

一开始只开了long long 爆炸 调了半天

posted @ 2018-07-23 22:13  wawawa8  阅读(144)  评论(0编辑  收藏  举报