BZOJ3570 : DZY Loves Physics I

考虑两个质量均为m,速度分别v1、v2的小球发生完全弹性碰撞的影响:

由动能守恒得:

$\frac{1}{2}mv_1^2+\frac{1}{2}mv_2^2=\frac{1}{2}mv_1'^2+\frac{1}{2}mv_2'^2$
$v_1^2+v_2^2=v_1'^2+v_2'^2$

由动量守恒得:

$mv_1+mv_2=mv_1'+mv_2'$
$v_1+v_2=v_1'+v_2'$
$v_1^2+v_2^2+2v_1v_2=v_1'^2+v_2'^2+2v_1'v_2'$

所以

$v_1v_2=v_1'v_2'$
$v_1'=v_2$
$v_2'=v_1$

结论:两个质量相同的小球发生完全弹性碰撞后交换速度。

 

由于询问的是第k小的速率,并没有要求是哪个小球,所以可以视为小球并没有发生碰撞,而是直接按原速度穿过去,所以直接计算出每个小球在t时刻的速度就可以了。

 

现在考虑怎么求速度:

每一时刻加速度$av=C$

而加速度可以看做是速度函数的导数,

设$f(x)$为x时刻的速度,$f(0)=v$,$f(x)f'(x)=C$

解得

$f(x)=\sqrt{2Cx+v^2}$

 

因为在t时刻,影响最终速度排名的只有初速度v,所以只需要用数据结构维护v的顺序就可以了。

时间复杂度$O((n+q)\log n)$

 

 

#include<cstdio>
#include<cmath>
#define N 200010
using namespace std;
typedef long long ll;
const double A=0.8;
int n,c,x,y,z,size[N],son[N][2],val[N],f[N],tot,root,data[N],id[N],cnt;
int ins(int x,int p){
  size[x]++;
  int b=p>=val[x];
  if(!son[x][b]){
    son[x][b]=++tot;f[tot]=x;size[tot]=1;
    val[tot]=p;
    return tot;
  }else return ins(son[x][b],p);
}
void dfs(int x){
  if(son[x][0])dfs(son[x][0]);
  data[++cnt]=val[x];id[cnt]=x;
  if(son[x][1])dfs(son[x][1]);
}
int build(int fa,int l,int r){
  int mid=(l+r)>>1,x=id[mid];
  f[x]=fa;son[x][0]=son[x][1]=0;size[x]=1;
  val[x]=data[mid];
  if(l==r)return x;
  if(l<mid)size[x]+=size[son[x][0]=build(x,l,mid-1)];
  if(r>mid)size[x]+=size[son[x][1]=build(x,mid+1,r)];
  return x;
}
inline int rebuild(int x){
  cnt=0;dfs(x);return build(f[x],1,cnt);
}
inline void insert(int p){
  if(!root){root=tot=size[1]=1;val[1]=p;return;}
  int x=ins(root,p);
  int deep=0;int z=x;while(f[z])z=f[z],deep++;
  if(deep<log(tot)/log(1/A))return;
  while((double)size[son[x][0]]<A*size[x]&&(double)size[son[x][1]]<A*size[x])x=f[x];
  if(!x)return;
  if(x==root){root=rebuild(x);return;}
  int y=f[x],b=son[y][1]==x,now=rebuild(x);
  son[y][b]=now;
}
inline int kth(int k){
  int x=root,sum;
  while(1){
    sum=size[son[x][0]]+1;
    if(k==sum)return val[x];
    if(k<sum)x=son[x][0];else k-=sum,x=son[x][1];
  }
}
inline void read(int&a){
  char c;bool f=0;a=0;
  while(!((((c=getchar())>='0')&&(c<='9'))||(c=='-')));
  if(c!='-')a=c-'0';else f=1;
  while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';
  if(f)a=-a;
}
int main(){
  read(n);read(c);
  while(n--)read(x),read(y),read(z),insert(x);
  read(n);
  while(n--){
    read(x);
    if(x)read(y),read(z),z=kth(z),printf("%.3f\n",sqrt(2*(ll)c*(ll)y+(ll)z*(ll)z));
    else read(x),read(y),read(y),insert(x);
  }
  return 0;
}

 

  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值