zoukankan      html  css  js  c++  java
  • bzoj4821 && luogu3707 SDOI2017相关分析(线段树,数学)

    题目大意

    给定n个元素的数列,每一个元素有x和y两种元素,现在有三种操作:

    (1 L R)
    (xx)([l,r])的元素的(x_i)的平均值,(yy)同理


    (frac{sum_{i=L}^R(x_i-xx)(y_i-yy)} {sum_{i=L}^R(xi-xx)^2})

    $2 L R S T ( 将)[L,R](中的每个元素的)x_i(+S,)y_i$+T

    $3 L R S T ( 对于)[L,R](中的每个元素,设其为)i(,将它的)x_i(改为)S+i(,)y_i(改为)T+i$

    其中(n le 100000 , mle100000)


    要是回答1询问的话,首先需要将线段树维护一个每个元素的x的平方的和、x的和、y的和,以及每一个元素x*y的和

    那么我们就开一个struct来记录这些值

    struct Node{
    	double sx,sy,sqr,xy,sum;
    };
    

    up数组的话,和普通的线段树差不多

    void up(int root)
    {
    	f[root].sx=f[2*root].sx+f[2*root+1].sx;
    	f[root].sy=f[2*root].sy+f[2*root+1].sy;
    	f[root].sqr=f[2*root].sqr+f[2*root+1].sqr;
    	f[root].xy=f[2*root].xy+f[2*root+1].xy;
    }
    

    对于pushdown,我们首先考虑增加操作,对于一个区间([l,r])
    (sum (x_i+S)) = (sum x_i +(r-l+1) imes S)
    (sum (y_i+T)) = (sum y_i +(r-l+1) imes T)
    (sum(x_i+S)^2) = (sum x_i^2 + 2 imes sum x_i imes S +S^2)
    (sum(x_I+S)(y_i+T)) = (sum x_i y_i) + (T imes sum x_i)+(S imes sum y_i)+((r-l+1) imes T imes S)

    经过一波操作,就可以直接在原来的基础上进行加法的操作了
    注意!!! 先更新乘法那些,再更新加法

    if (add[root].x || add[root].y)
    	{
    	   add[2*root].x+=add[root].x;
    	   add[2*root+1].x+=add[root].x;
    	   add[2*root].y+=add[root].y;
    	   add[2*root+1].y+=add[root].y;
    	   f[2*root].sqr+=(mid-l+1)*add[root].x*add[root].x+2*f[2*root].sx*add[root].x;
    	   f[2*root+1].sqr+=(r-mid)*add[root].x*add[root].x+2*f[2*root+1].sx*add[root].x;
    	   f[2*root].xy+=(mid-l+1)*add[root].x*add[root].y+f[2*root].sx*add[root].y+f[2*root].sy*add[root].x;   
    	   f[2*root+1].xy+=(r-mid)*add[root].x*add[root].y+f[2*root+1].sx*add[root].y+f[2*root+1].sy*add[root].x; 
    	   f[2*root].sx+=(mid-l+1)*add[root].x;
    	   f[2*root+1].sx+=(r-mid)*add[root].x;
    	   f[2*root].sy+=(mid-l+1)*add[root].y;
    	   f[2*root+1].sy+=(r-mid)*add[root].y;      
           add[root].x=0;
           add[root].y=0;
    	}
    

    那么那么那么,对于有覆盖操作的的呢?
    我们可以这么想,把覆盖分解成两步
    1.把(x_i)(y_i)修改成(i)
    2.将(x_i+S)(y_i+T)

    那么我们思考,全部覆盖成(i)应该怎么做呢QwQ

    首先,一旦一个区间被打了覆盖标记,那么之前的add 的标记就需要全部清空

    我们会发现修改完的序列是这样的(1,2,3,4,5.....)

    (sum_{i=1}^n i^2 = frac {n(n+1)(2n+1)}{6})

    所以,对于一个区间([l,r])

    (sum x_i = sum y_i = frac{(r-l+1)(r+l)}{2})


    (sum x_i^2 = sum x_i y_i = frac {(r+1)r(2r+1)}{6} - frac{l(l-1)(2l-1)}{6})

    在下传标记的时候,当把覆盖标记下传完之后,把传到的那两个子区间 的 (add) 清空
    一定记得把add的标记清空!!!!!!

    if (flag[root])
        {
            flag[2*root+1]=1;flag[2*root]=1;flag[root]=0;add[2*root].x=add[2*root].y=add[2*root+1].x=add[2*root+1].y=0;
            f[2*root].sx=(l+mid)*(mid-l+1)/2;
            f[2*root].sy=(l+mid)*(mid-l+1)/2;
            f[2*root+1].sx=(r+mid+1)*(r-mid-1+1)/2;
            f[2*root+1].sy=(r+mid+1)*(r-mid-1+1)/2;
            f[2*root].xy=f[2*root].sqr=(mid+1)*mid*(2*mid+1)/6-(l-1)*l*(2*l-1)/6;
            f[2*root+1].xy=f[2*root+1].sqr=(r+1)*r*(2*r+1)/6-(mid)*(mid+1)*(2*mid+1)/6;
        }
    

    build也和普通的线段树没什么区别

    void build(int root,int l,int r)
    {
        if (l==r)
        {
            f[root].sx=a[l].x;
            f[root].sy=a[l].y;
            f[root].xy=a[l].x*a[l].y;
            f[root].sqr=a[l].x*a[l].x;
            return;
        }
        int mid = (l+r) >> 1;
        build(2*root,l,mid);
        build(2*root+1,mid+1,r);
        up(root);
    }
    

    再就是update和change了 QwQ我的做法是把区间加和区间赋值分开写,其实和pushdown的操作基本上完全一样
    直接上代码了

    void update(int root,int l,int r,int x,int y,double px,double py)
    {
        if (x<=l && r<=y)
        {
            add[root].x+=px;
            add[root].y+=py;
            f[root].xy+=(double)(r-l+1)*px*py+(double)f[root].sx*py+(double)f[root].sy*px;
            f[root].sqr+=(double)(r-l+1)*px*px+(double)f[root].sx*px*2;
            f[root].sx+=(double)(r-l+1)*px;
            f[root].sy+=(double)(r-l+1)*py;
            return;
        }
        pushdown(root,l,r);
        int mid = (l+r) >> 1;
        if (x<=mid) update(2*root,l,mid,x,y,px,py);
        if (y>mid) update(2*root+1,mid+1,r,x,y,px,py);
        up(root);
    }
    
    void change(int root,int l,int r,int x,int y)
    {
        if (x<=l && r<=y)
        {
            flag[root]=1;
            f[root].sy=f[root].sx=(double)(r+l)*(double)(r-l+1)/2.0;
            f[root].xy=f[root].sqr=(double)(r+1)*(double)r*(double)(2*r+1)/6.0-(double)(l-1)*(double)l*(double)(2*l-1)/6.0;
            add[root].x=add[root].y=0;
            return;
        }
        pushdown(root,l,r);
        int mid = (l+r) >> 1;
        if (x<=mid) change(2*root,l,mid,x,y);
        if (y>mid) change(2*root+1,mid+1,r,x,y);
        up(root);
    }
    

    求答案的部分就不放了
    其他的emmmm 也很裸 直接上全部的代码

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<queue>
    #include<map>
    #include<vector>
    
    using namespace std;
    
    inline int read()
    {
      int x=0,f=1;char ch=getchar();
      while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
      while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
      return x*f;
    }
    
    const int maxn = 3e5+1e2;
    
    struct Node{
        double sx,sy,sqr,xy,sum;
    };
    
    struct po{
        double x,y;
    };
    
    Node f[4*maxn];
    po add[4*maxn],a[maxn];
    bool flag[4*maxn];
    int n,m;
    
    void up(int root)
    {
        f[root].sx=f[2*root].sx+f[2*root+1].sx;
        f[root].sy=f[2*root].sy+f[2*root+1].sy;
        f[root].sqr=f[2*root].sqr+f[2*root+1].sqr;
        f[root].xy=f[2*root].xy+f[2*root+1].xy;
    //	f[root].sum=f[2*root].sum+f[2*root+1].sum;	
    }
    
    void pushdown(int root,int ll,int rr)
    {
        double mid = (ll+rr)/2;
        double l=ll,r=rr;
        if (flag[root])
        {
            flag[2*root+1]=1;flag[2*root]=1;flag[root]=0;add[2*root].x=add[2*root].y=add[2*root+1].x=add[2*root+1].y=0;
            f[2*root].sx=(l+mid)*(mid-l+1)/2;
            f[2*root].sy=(l+mid)*(mid-l+1)/2;
            f[2*root+1].sx=(r+mid+1)*(r-mid-1+1)/2;
            f[2*root+1].sy=(r+mid+1)*(r-mid-1+1)/2;
            f[2*root].xy=f[2*root].sqr=(mid+1)*mid*(2*mid+1)/6-(l-1)*l*(2*l-1)/6;
            f[2*root+1].xy=f[2*root+1].sqr=(r+1)*r*(2*r+1)/6-(mid)*(mid+1)*(2*mid+1)/6;
        }	
        if (add[root].x || add[root].y)
        {
           add[2*root].x+=add[root].x;
           add[2*root+1].x+=add[root].x;
           add[2*root].y+=add[root].y;
           add[2*root+1].y+=add[root].y;
           f[2*root].sqr+=(mid-l+1)*add[root].x*add[root].x+2*f[2*root].sx*add[root].x;
           f[2*root+1].sqr+=(r-mid)*add[root].x*add[root].x+2*f[2*root+1].sx*add[root].x;
           f[2*root].xy+=(mid-l+1)*add[root].x*add[root].y+f[2*root].sx*add[root].y+f[2*root].sy*add[root].x;   
           f[2*root+1].xy+=(r-mid)*add[root].x*add[root].y+f[2*root+1].sx*add[root].y+f[2*root+1].sy*add[root].x; 
           f[2*root].sx+=(mid-l+1)*add[root].x;
           f[2*root+1].sx+=(r-mid)*add[root].x;
           f[2*root].sy+=(mid-l+1)*add[root].y;
           f[2*root+1].sy+=(r-mid)*add[root].y;      
           add[root].x=0;
           add[root].y=0;
        }
    }
    
    void build(int root,int l,int r)
    {
        if (l==r)
        {
            f[root].sx=a[l].x;
            f[root].sy=a[l].y;
            f[root].xy=a[l].x*a[l].y;
            f[root].sqr=a[l].x*a[l].x;
            return;
        }
        int mid = (l+r) >> 1;
        build(2*root,l,mid);
        build(2*root+1,mid+1,r);
        up(root);
    }
    
    void update(int root,int l,int r,int x,int y,double px,double py)
    {
        if (x<=l && r<=y)
        {
            add[root].x+=px;
            add[root].y+=py;
            f[root].xy+=(double)(r-l+1)*px*py+(double)f[root].sx*py+(double)f[root].sy*px;
            f[root].sqr+=(double)(r-l+1)*px*px+(double)f[root].sx*px*2;
            f[root].sx+=(double)(r-l+1)*px;
            f[root].sy+=(double)(r-l+1)*py;
            return;
        }
        pushdown(root,l,r);
        int mid = (l+r) >> 1;
        if (x<=mid) update(2*root,l,mid,x,y,px,py);
        if (y>mid) update(2*root+1,mid+1,r,x,y,px,py);
        up(root);
    }
    
    void change(int root,int l,int r,int x,int y)
    {
        if (x<=l && r<=y)
        {
            flag[root]=1;
            f[root].sy=f[root].sx=(double)(r+l)*(double)(r-l+1)/2.0;
            f[root].xy=f[root].sqr=(double)(r+1)*(double)r*(double)(2*r+1)/6.0-(double)(l-1)*(double)l*(double)(2*l-1)/6.0;
            add[root].x=add[root].y=0;
            return;
        }
        pushdown(root,l,r);
        int mid = (l+r) >> 1;
        if (x<=mid) change(2*root,l,mid,x,y);
        if (y>mid) change(2*root+1,mid+1,r,x,y);
        up(root);
    }
    
    double queryxy(int root,int l,int r,int x,int y)
    {
        if (x<=l && r<=y)
        {
            return f[root].xy;
        }
        pushdown(root,l,r);
        int mid = (l+r)>>1;
        double ans=0;
        if (x<=mid) ans+=queryxy(2*root,l,mid,x,y);
        if (y>mid) ans+=queryxy(2*root+1,mid+1,r,x,y);
        return ans;
    }
    
    double querysqr(int root,int l,int r,int x,int y)
    {
        if (x<=l && r<=y)
        {
            return f[root].sqr;
        }
        pushdown(root,l,r);
        int mid = (l+r)>>1;
        double ans=0;
        if (x<=mid) ans+=querysqr(2*root,l,mid,x,y);
        if (y>mid) ans+=querysqr(2*root+1,mid+1,r,x,y);
        return ans;
    }
    
    double querysx(int root,int l,int r,int x,int y)
    {
        if (x<=l && r<=y)
        {
            return f[root].sx;
        }
        pushdown(root,l,r);
        int mid = (l+r)>>1;
        double ans=0;
        if (x<=mid) ans+=querysx(2*root,l,mid,x,y);
        if (y>mid) ans+=querysx(2*root+1,mid+1,r,x,y);
        return ans;
    }
    
    double querysy(int root,int l,int r,int x,int y)
    {
        if (x<=l && r<=y)
        {
            return f[root].sy;
        }
        pushdown(root,l,r);
        int mid = (l+r)>>1;
        double ans=0;
        if (x<=mid) ans+=querysy(2*root,l,mid,x,y);
        if (y>mid) ans+=querysy(2*root+1,mid+1,r,x,y);
        return ans;
    }
    
    double solve(int l,int r)
    {
       double ax = querysx(1,1,n,l,r)/(double)(r-l+1);
       double ay = querysy(1,1,n,l,r)/(double)(r-l+1);
       update(1,1,n,l,r,-ax,-ay);
       double ans = queryxy(1,1,n,l,r)/querysqr(1,1,n,l,r);
       update(1,1,n,l,r,ax,ay);
       return ans;
    }
    
    int main()
    {
      scanf("%d%d",&n,&m);
      for (int i=1;i<=n;i++) scanf("%lf",&a[i].x);
      for (int i=1;i<=n;i++) scanf("%lf",&a[i].y);
      build(1,1,n);
      for (int i=1;i<=m;i++)
      {
      	 int opt;
      	 int x,y;
         double px,py;
      	 opt=read();
      	 if (opt==1)
      	 {
      	 	 x=read(),y=read();printf("%.10lf
    ",solve(x,y));
           }
         if (opt==2)
         {
         	x=read(),y=read();
         	scanf("%lf%lf",&px,&py);
         	update(1,1,n,x,y,px,py);
         }
         if (opt==3)
         {
         	x=read(),y=read();
         	scanf("%lf%lf",&px,&py);
         	change(1,1,n,x,y);
         	update(1,1,n,x,y,px,py);
         }
      }
      return 0;
    }
    
    

    QwQ共勉

  • 相关阅读:
    saltstack笔记
    saltstack学习篇
    tomcat学习篇
    memcache笔记
    sed、awk学习篇
    javascript function call
    jvm性能调优工具
    spring boot 单元测试
    activemq 分布式事务
    sringboot 集成dobbo2.5.3
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10160708.html
Copyright © 2011-2022 走看看