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\n",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; }