水题-sdoi2017-相关分析

线段树.维护四个值: x,y,xy,x2
3操作拆分成一个赋值操作外加一个2操作就行了。预处理一下平方和之类的就好了。
注意几个问题:
1.不要用long long(会爆long long),要用double.
2.最后是把2,3操作的lazy标记分开写。处理3标记时,直接清空2标记.

贴个代码:

#include
#include
using namespace std;
#define MAXN 105000
//#define LL long long
#define ls (p<<1)
#define rs (p<<1|1)
void _r(int& x,bool f=0)
{
    char c=getchar();
    while(c<'0'||c>'9')
    {
        f|=(c=='-');
        c=getchar();
    }
    for(x=0;c>='0'&&c<='9';c=getchar())
    {
        x=(x<<1)+(x<<3)+c-'0';
    }
    x=f?-x:x;
    return ;
}

double vx[MAXN<<2],vy[MAXN<<2],vxx[MAXN<<2],vxy[MAXN<<2],tx[MAXN<<2],ty[MAXN<<2],ti[MAXN<<2],x_2[MAXN],x_1[MAXN];
int x[MAXN],y[MAXN];
int n,m;
void merge(int p,int l,int r)
{
    vx[p]=vx[l]+vx[r];
    vy[p]=vy[l]+vy[r];
    vxx[p]=vxx[l]+vxx[r];
    vxy[p]=vxy[l]+vxy[r];
    return ;
}
void build(int p,int l,int r)
{
    if(l==r)
    {
        vx[p]=x[l];
        vy[p]=y[l];
        vxx[p]=1ll*x[l]*x[l];
        vxy[p]=1ll*x[l]*y[l];
        return ;
    }
    int mid=(l+r)>>1; 
    build(ls,l,mid);
    build(rs,mid+1,r);
    merge(p,ls,rs);
    return ;
}
void up1(int p,int l,int r)
{
    vx[p]=vy[p]=x_1[r]-x_1[l-1];
    vxx[p]=vxy[p]=x_2[r]-x_2[l-1];
    ti[p]=1;
    tx[p]=ty[p]=0;
    return ;
}
void up2(int p,int l,int r,double dx,double dy)
{
    tx[p]+=dx;
    ty[p]+=dy;
    vxy[p]+=vx[p]*dy+vy[p]*dx+dx*dy*1.0*(r-l+1);
    vxx[p]+=vx[p]*dx*2ll+dx*dx*1.0*(r-l+1);
    vx[p]+=dx*1.0*(r-l+1);
    vy[p]+=dy*1.0*(r-l+1);
    return ;
}
void push(int p,int l,int r)
{
    int mid=(l+r)>>1; 
    if(ti[p])
    {
         up1(ls,l,mid);
         up1(rs,mid+1,r);
         ti[p]=0;
    }
    if(tx[p]||ty[p])
    {
        up2(ls,l,mid,tx[p],ty[p]);
        up2(rs,mid+1,r,tx[p],ty[p]);
        tx[p]=ty[p]=0;
    }
    return ;
}
void add(int p,int l,int r,int x,int y,double dx,double dy)
{
    if(l>=x&&r<=y)
    {
        up2(p,l,r,dx,dy);
        return ;
    }
    push(p,l,r);
    int mid=(l+r)>>1;
    if(x<=mid)
    {
        add(ls,l,mid,x,y,dx,dy);
    }
    if(y>mid)
    {
        add(rs,mid+1,r,x,y,dx,dy);
    }
    merge(p,ls,rs);
    return ;
}
void change(int p,int l,int r,int x,int y)
{
    if(l>=x&&r<=y)
    {
        up1(p,l,r);
        return ;
    }
    push(p,l,r);
    int mid=(l+r)>>1;
    if(x<=mid)
    {
        change(ls,l,mid,x,y);
    }
    if(y>mid)
    {
        change(rs,mid+1,r,x,y);
    }
    merge(p,ls,rs);
}
struct node
{
    double x,y,xx,xy;
    node(double a=0,double b=0,double c=0,double d=0)
    {
        x=a;
        y=b;
        xx=c;
        xy=d;
    }
    node operator + (node p)
    {
        return node(x+p.x,y+p.y,xx+p.xx,xy+p.xy);
    }
};
node query(int p,int l,int r,int x,int y)
{
    if(l>=x&&r<=y)
    {
        return node(vx[p],vy[p],vxx[p],vxy[p]);
    }
    push(p,l,r);
    int mid=(l+r)>>1;
    node t=node(0.0,0.0,0.0,0.0);
    if(x<=mid)
    {
        t=t+query(ls,l,mid,x,y);
    }
    if(y>mid)
    {
        t=t+query(rs,mid+1,r,x,y);
    }
    return t;
}
int main()
{
    _r(n);
    _r(m);
    for(int i=1;i<=n;i++)
    {
        _r(x[i]);
        x_1[i]=x_1[i-1]+1.0*i;
        x_2[i]=x_2[i-1]+1.0*i*i;
    }
    for(int i=1;i<=n;i++)
    {
        _r(y[i]);
    }
    node p;
    build(1,1,n);
    for(int i=1,q,x,y,s,t;i<=m;i++)
    {
        _r(q);
        _r(x);
        _r(y);
        if(q==1)
        {
            p=query(1,1,n,x,y);
            printf("%.10lf\n",(p.xy-p.x*p.y/(y-x+1))/(p.xx-p.x*p.x/(y-x+1)));
        }
        if(q==2)
        {
            _r(s);
            _r(t);
            add(1,1,n,x,y,s,t);
        }
        if(q==3)
        {
            _r(s);
            _r(t);
            change(1,1,n,x,y);
            add(1,1,n,x,y,s,t);
        }
    }
    return 0;
}

你可能感兴趣的:(题解)