[BZOJ]4821: [Sdoi2017]相关分析 线段树

来源:互联网 发布:sql server 2008 合计 编辑:程序博客网 时间:2024/06/06 18:31

Description

Frank对天文学非常感兴趣,他经常用望远镜看星星,同时记录下它们的信息,比如亮度、颜色等等,进而估算出
星星的距离,半径等等。Frank不仅喜欢观测,还喜欢分析观测到的数据。他经常分析两个参数之间(比如亮度和
半径)是否存在某种关系。现在Frank要分析参数X与Y之间的关系。他有n组观测数据,第i组观测数据记录了x_i和
y_i。他需要一下几种操作1 L,R:用直线拟合第L组到底R组观测数据。用xx表示这些观测数据中x的平均数,用yy
表示这些观测数据中y的平均数,即
xx=Σx_i/(R-L+1)(L<=i<=R)
yy=Σy_i/(R-L+1)(L<=i<=R)
如果直线方程是y=ax+b,那么a应当这样计算:
a=(Σ(x_i-xx)(y_i-yy))/(Σ(x_i-xx)(x_i-xx)) (L<=i<=R)
你需要帮助Frank计算a。
2 L,R,S,T:
Frank发现测量数据第L组到底R组数据有误差,对每个i满足L <= i <= R,x_i需要加上S,y_i需要加上T。
3 L,R,S,T:
Frank发现第L组到第R组数据需要修改,对于每个i满足L <= i <= R,x_i需要修改为(S+i),y_i需要修改为(T+i)。

题解:

无脑线段树,就是推公式,维护一大堆东西,注意标记下传,就好了。和上次那道求期望的线段树有点像。

代码:

#include<bits/stdc++.h>using namespace std;#define LL long longconst int Maxn=100010;int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}    return x*f;}struct Tree{int l,r,lc,rc;double sx,sy,sxx,sxy,s,t;bool tf1,tf2;}tr[Maxn*2+100];int trlen=0;double X[Maxn],Y[Maxn],ss[Maxn];void push_up(int x){    int lc=tr[x].lc,rc=tr[x].rc;    tr[x].sx=tr[lc].sx+tr[rc].sx;    tr[x].sy=tr[lc].sy+tr[rc].sy;    tr[x].sxx=tr[lc].sxx+tr[rc].sxx;    tr[x].sxy=tr[lc].sxy+tr[rc].sxy;}void build(int l,int r){    int t=++trlen;    tr[t].l=l;tr[t].r=r;tr[t].s=tr[t].t=0.0;tr[t].tf1=tr[t].tf2=false;    if(l==r)    {        tr[t].sx=X[tr[t].l];tr[t].sy=Y[tr[t].l];        tr[t].sxx=X[tr[t].l]*X[tr[t].l];tr[t].sxy=X[tr[t].l]*Y[tr[t].l];    }    else    {        int mid=l+r>>1;        tr[t].lc=trlen+1;build(l,mid);        tr[t].rc=trlen+1;build(mid+1,r);        push_up(t);    }}void Add(int x,double s,double t){    double l=(double)(tr[x].l),r=(double)(tr[x].r);    tr[x].sxx+=2.0*(tr[x].sx)*s+(r-l+1.0)*s*s;    tr[x].sxy+=tr[x].sx*t+tr[x].sy*s+(r-l+1.0)*s*t;    tr[x].sx+=(r-l+1.0)*s;    tr[x].sy+=(r-l+1.0)*t;    tr[x].s+=s;tr[x].t+=t;    if(!tr[x].tf2)tr[x].tf1=true;}void Change(int x,double s,double t){    double l=(double)(tr[x].l),r=(double)(tr[x].r),sum=(l+r)*(r-l+1.0)/2.0;    tr[x].s=s;tr[x].t=t;    tr[x].sx=sum+(r-l+1.0)*s;    tr[x].sy=sum+(r-l+1.0)*t;    tr[x].sxx=ss[tr[x].r]-ss[tr[x].l-1]+2*sum*s+(r-l+1.0)*s*s;    tr[x].sxy=ss[tr[x].r]-ss[tr[x].l-1]+(s+t)*sum+(r-l+1.0)*s*t;    tr[x].tf1=false;tr[x].tf2=true;}void push_down(int x){    int lc=tr[x].lc,rc=tr[x].rc;    if(tr[x].tf1)    {        tr[x].tf1=false;        Add(lc,tr[x].s,tr[x].t);Add(rc,tr[x].s,tr[x].t);    }    else    {        tr[x].tf2=false;        Change(lc,tr[x].s,tr[x].t);Change(rc,tr[x].s,tr[x].t);    }    tr[x].s=tr[x].t=0.0;}Tree query(int now,int l,int r){    if(tr[now].l==l&&tr[now].r==r)return tr[now];    int lc=tr[now].lc,rc=tr[now].rc,mid=tr[now].l+tr[now].r>>1;    Tree re;    if(tr[now].tf1||tr[now].tf2)push_down(now);    if(r<=mid)re=query(lc,l,r);    else if(l>mid)re=query(rc,l,r);    else    {        Tree L=query(lc,l,mid),R=query(rc,mid+1,r);        re.sx=L.sx+R.sx;re.sy=L.sy+R.sy;re.sxx=L.sxx+R.sxx;re.sxy=L.sxy+R.sxy;    }    push_up(now);    return re;}void change(int now,int l,int r,double s,double t){    if(tr[now].l==l&&tr[now].r==r){Change(now,s,t);return;}    int lc=tr[now].lc,rc=tr[now].rc,mid=tr[now].l+tr[now].r>>1;    if(tr[now].tf1||tr[now].tf2)push_down(now);    if(r<=mid)change(lc,l,r,s,t);    else if(l>mid)change(rc,l,r,s,t);    else change(lc,l,mid,s,t),change(rc,mid+1,r,s,t);    push_up(now);}void add(int now,int l,int r,double s,double t){    if(tr[now].l==l&&tr[now].r==r){Add(now,s,t);return;}    int lc=tr[now].lc,rc=tr[now].rc,mid=tr[now].l+tr[now].r>>1;    if(tr[now].tf1||tr[now].tf2)push_down(now);    if(r<=mid)add(lc,l,r,s,t);    else if(l>mid)add(rc,l,r,s,t);    else add(lc,l,mid,s,t),add(rc,mid+1,r,s,t);    push_up(now);}int n,m;int main(){    n=read();m=read();    ss[0]=0.0;for(int i=1;i<=n;i++)ss[i]=ss[i-1]+(double)(i)*(double)(i);    for(int i=1;i<=n;i++)scanf("%lf",&X[i]);    for(int i=1;i<=n;i++)scanf("%lf",&Y[i]);    build(1,n);    while(m--)    {        int op,l,r;        double s,t;        op=read();l=read();r=read();        if(op==1)        {            Tree ans=query(1,l,r);            double xx=ans.sx/(double)(r-l+1),yy=ans.sy/(double)(r-l+1);            double a=(ans.sxy-yy*ans.sx-xx*ans.sy+(double)(r-l+1)*xx*yy)/(ans.sxx-2.0*ans.sx*xx+(double)(r-l+1)*xx*xx);            printf("%.10lf\n",a);        }        else        {            scanf("%lf%lf",&s,&t);            if(op==2)add(1,l,r,s,t);            else change(1,l,r,s,t);        }    }}
原创粉丝点击