• [bzoj4821] [Sdoi2017] 相关分析


    Description

    (Frank) 对天文学非常感兴趣,他经常用望远镜看星星,同时记录下它们的信息,比如亮度、颜色等等,进而估算出星星的距离,半径等等。(Frank) 不仅喜欢观测,还喜欢分析观测到的数据。他经常分析两个参数之间(比如亮度和半径)是否存在某种关系。现在 (Frank) 要分析参数 (X)(Y) 之间的关系。他有 (n) 组观测数据,第i组观测数据记录了 (x_i)(y_i)
    他需要一下几种操作:

    (1) (L),(R):用直线拟合第 (L) 组到第 (R) 组观测数据。用 (xx) 表示这些观测数据中 (x) 的平均数,用 (yy)
    表示这些观测数据中 (y) 的平均数,即
    (xx=frac{sum x_i}{R-L+1}(L leq i leq R))
    (yy=frac{sum y_i}{R-L+1}(L leq i leq R))
    如果直线方程是 (y=ax+b) ,那么 (a) 应当这样计算:
    (a=frac{sum(x_i-xx)(y_i-yy)}{sum (x_i-xx)(x_i-xx)} (L leq i leq R))
    你需要帮助 (Frank) 计算 (a)

    (2) (L),(R),(S),(T)
    (Frank) 发现测量数据第 (L) 组到底 (R) 组数据有误差,对每个 (i) 满足 (L leq i leq R)(x_i) 需要加上 (S)(y_i) 需要加上 (T)

    (3) (L),(R),(S),(T)
    (Frank)发现第 (L) 组到第 (R) 组数据需要修改,对于每个 (i) 满足 (L leq i leq R)(x_i) 需要修改为 ((S+i))(y_i) 需要修改为 ((T+i))

    Input

    第一行两个数 (n),(m),表示观测数据组数和操作次数。
    接下来一行 (n) 个数,第 (i) 个数是 (x_i)
    接下来一行 (n) 个数,第 (i) 个数是 (y_i)
    接下来 (m) 行,表示操作,格式见题目描述。
    (1 leq n,m leq 10^5,0 leq |S|,|T|,|x_i|,|y_i| leq 10^5)
    保证 (1) 操作不会出现分母为 (0) 的情况。

    Output

    对于每个 (1) 操作,输出一行,表示直线斜率 (a)
    选手输出与标准输出的绝对误差不超过 (10^-5) 即为正确。

    Sample Input

    3 5

    1 2 3

    1 2 3

    1 1 3

    2 2 3 -3 2

    1 1 2

    3 1 2 2 1

    1 1 3

    Sample Output

    1.0000000000

    -1.5000000000

    -0.6153846154


    想法

    明明很简单的一道线段树,我不知道 (debug) 了多长时间。。。

    首先拆式子,然后发现我们要维护的是区间 (sum x_i) , (sum y_i) , (sum x_i^2) , (sum x_i cdot y_i)
    注意有两个操作——
    操作2就直接区间加维护 (lazy) 就行了
    操作3就想把区间内的点 (set)(i) ,然后就变成操作2了。

    然而我为啥 (debug) 了那么长时间呢 (qwq) ,全是 (lazy) 下放问题!!!
    (lazy) 下放的重点是 修改操作可叠加性
    比如区间加,某个区间第一次加 (x) ,第二次加 (y) 等价于一次加 (x+y)
    然而这个问题中的2个操作是不能叠加的!所以出现了操作的优先级问题,类似加与乘结合。
    这道题中 (set) 的优先级就更大,进行 (set) 的时候需要把当前点及其子节点(S\_lazy)(T\_lazy) 都清空。但当然不用在 (set) 的时候都清空,只需清空当前点的,之后在 (pushdown) 的时候注意一下如果要把 (set) 操作 (push) 下去,则子节点的 (S\_lazy=该节点的S\_lazy) ,否则 子结点的 $ S _ lazy+=该节点的 S _ lazy$

    !!教训!!
    当线段树中出现多种修改操作时,一定要谨慎!注意优先级问题和各种奇怪细节 (qwq)


    代码

    一把辛酸泪。。。

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    int read(){
    	int x=0,f=1;
    	char ch=getchar();
    	while(!isdigit(ch) && ch!='-') ch=getchar();
    	if(ch=='-') f=-1,ch=getchar();
    	while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    	return x*f;
    }
    
    const int N = 200005;
    typedef long long ll;
    
    int n,m;
    double xi[N],yi[N];
    
    int root,cnt,ch[N][2],lazy[N];
    double X[N],Y[N],xx[N],xy[N],S[N],T[N];
    double e1[N],e2[N];
    void update(int x){
    	X[x]=X[ch[x][0]]+X[ch[x][1]];
    	Y[x]=Y[ch[x][0]]+Y[ch[x][1]];
    	xx[x]=xx[ch[x][0]]+xx[ch[x][1]];
    	xy[x]=xy[ch[x][0]]+xy[ch[x][1]];
    }
    void build(int x,int l,int r){
    	lazy[x]=S[x]=T[x]=0;
    	if(l==r){
    		X[x]=xi[l]; Y[x]=yi[l];
    		xx[x]=X[x]*X[x];
    		xy[x]=X[x]*Y[x];
    		e1[x]=l; e2[x]=1ll*l*l;
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(ch[x][0]=++cnt,l,mid);
    	build(ch[x][1]=++cnt,mid+1,r);
    	update(x);
    	e1[x]=e1[ch[x][0]]+e1[ch[x][1]];
    	e2[x]=e2[ch[x][0]]+e2[ch[x][1]];
    }
    void setting(int x){
    	lazy[x]=1; S[x]=T[x]=0;
    	X[x]=Y[x]=e1[x];
    	xx[x]=xy[x]=e2[x];
    }
    void adding(int x,int l,int r,double s,double t){
    	int len=(r-l+1);
    	xy[x]=xy[x]+Y[x]*s+X[x]*t+1ll*len*s*t;
    	xx[x]=xx[x]+X[x]*s*2+1ll*len*s*s;
    	X[x]+=1ll*len*s;
    	Y[x]+=1ll*len*t;
    	S[x]+=s; T[x]+=t; 
    }
    void pushdown(int x,int l,int r){
    	if(lazy[x]){
    		setting(ch[x][0]); setting(ch[x][1]);
    		lazy[x]=0;
    		if(S[x] || T[x]){
    			int mid=(l+r)>>1;
    			adding(ch[x][0],l,mid,S[x],T[x]); S[ch[x][0]]=S[x];T[ch[x][0]]=T[x];
    			adding(ch[x][1],mid+1,r,S[x],T[x]); S[ch[x][1]]=S[x];T[ch[x][1]]=T[x];
    			S[x]=T[x]=0;
    		}
    	}
    	if(S[x] || T[x]){
    		int mid=(l+r)>>1;
    		adding(ch[x][0],l,mid,S[x],T[x]);
    		adding(ch[x][1],mid+1,r,S[x],T[x]);
    		S[x]=T[x]=0;
    	}
    }
    void set(int x,int l,int r,int L,int R){
    	if(L<=l && r<=R) { setting(x); return; }
    	pushdown(x,l,r);
    	int mid=(l+r)>>1;
    	if(L<=mid) set(ch[x][0],l,mid,L,R);
    	if(R>mid) set(ch[x][1],mid+1,r,L,R);
    	update(x);
    }
    void change(int x,int l,int r,int L,int R,double s,double t){
    	if(L<=l && r<=R) { adding(x,l,r,s,t); return; }
    	pushdown(x,l,r);
    	int mid=(l+r)>>1;
    	if(L<=mid) change(ch[x][0],l,mid,L,R,s,t);
    	if(R>mid) change(ch[x][1],mid+1,r,L,R,s,t);
    	update(x);
    }
    struct data{ 
    	double x,y,xx,xy; 
    
    	data operator + (const data &b) const{ return (data){x+b.x,y+b.y,xx+b.xx,xy+b.xy}; }
    
    	data operator += (const data &b) { return *this=*this+b; }
    };
    
    
    data ask(int x,int l,int r,int L,int R){
    	if(L<=l && r<=R) return (data){X[x],Y[x],xx[x],xy[x]};
    	pushdown(x,l,r);
    	int mid=(l+r)>>1;
    
    	data ret=(data){0,0,0,0};
    	if(L<=mid) ret+=ask(ch[x][0],l,mid,L,R);
    	if(R>mid) ret+=ask(ch[x][1],mid+1,r,L,R);
    	return ret;
    }
    double cal(int l,int r){
    
    	data c=ask(root,1,n,l,r);
    	int len=r-l+1;
    	double bx=c.x/(1.0*len),by=c.y/(1.0*len);
    	double p=c.xy-bx*by*len,q=c.xx-bx*bx*len;
    	return p/q;
    }
    
    int main()
    {
    	n=read(); m=read();
    	for(int i=1;i<=n;i++) xi[i]=read();
    	for(int i=1;i<=n;i++) yi[i]=read();
    	
    	int opt,l,r,s,t;
    	build(root=++cnt,1,n);
    	while(m--){
    		opt=read(); l=read(); r=read();
    		if(opt==1) printf("%.10lf
    ",cal(l,r));
    		else {
    			s=read(); t=read();
    			if(opt==3) set(root,1,n,l,r);
    			change(root,1,n,l,r,s,t);
    		}
    	}
    	
    	return 0;
    }
    
    既然选择了远方,便只顾风雨兼程
  • 相关阅读:
    Java I/O的典型使用方式
    搜索--hiho 骑士问题
    编程之美--水王(找出出现超过1/2的数)
    深入理解java虚拟机之类文件结构以及加载
    【转载】Java JVM 运行机制及基本原理
    整数的划分总结(转)
    java静态方法和非静态方法
    mongodb 运行错误总结
    MongoDb windows环境安装,附百度云链接
    JAVA解析Json数据
  • 原文地址:https://www.cnblogs.com/lindalee/p/11390086.html
Copyright © 2020-2023  润新知