一道线段树练习题

题意

在这里插入图片描述
注意收到的伤害值写的有点问题,实际上是 a 2 + j = 1 k ( A i , j C j ) 2 \sqrt{a^2+\sum_{j=1}^k(A_{i,j}-C_j)^2} ,没有后面的-a

数据范围

在这里插入图片描述

时限6S

解法

首先由于题目中的限制“选了第i个敌人就再也不能和1到i-1的敌人作战”,我们可以观察后得出dp: a n s [ i ] = m i n ( a n s [ u ] + j = 1 k ( A i , j A u , j ) 2 ) ans[i]=min(\sqrt{ans[u]+\sum_{j=1}^k(A_{i,j}-A_{u,j})^2})
这是 O ( N 2 ) O(N^2) 的,可以通过20pts.
然后考虑k=1时的情况:我们发现其实ans[i]的值和u没有什么关系,而是和 A u , 1 A_{u,1} 有关,所以考虑设一个新数组alfa,其中alfa[i]表示 A u , 1 = = i A_{u,1}==i 时,ans[u]最小是多少,然后对于第3个测试点,直接暴力维护alfa就可以通过了。
考虑4-5测试点,我们希望能快速维护类似alfa的东西:考虑beta数组,其中beta[j]表示当前 A i , 1 = = j A_{i,1}==j 的答案,那么每次计算出一个ans[i],都可以更新一些beta的值,然后我们发现由于 A A 数组的随机性,可以用线段树剪枝。每个位置维护所管辖区间的beta的最小值,然后修改时剪枝,具体看代码。
最后的50pts,因为多了一维,不能直接维护所有的beta了,所以我们转回去,考虑维护alfa,然后加上第二维的限制进行剪枝,然后卡常。。。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
const double inf=1e18;
inline int read(){
	char c=getchar();int t=0,f=1;
	while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
	while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
	return t*f; 
}
int n,k,a[maxn][3];
double dp[maxn];
double t[maxn];
#define ls rt<<1
#define rs rt<<1|1
inline void pushup(int rt){
	t[rt]=max(t[ls],t[rs]);
}
int ps[maxn];
inline void build(int rt,int l,int r){
	t[rt]=1e18;
	if(l==r){
		ps[l]=rt;
		return;
	}
	int mid=(l+r)>>1;
	build(ls,l,mid);build(rs,mid+1,r);
	pushup(rt);
}
inline void modify(int rt,int l,int r,int x,double val){
	double dis=0;
	if(l<=x&&x<=r)dis=0;
	else dis=min(abs(x-l),abs(r-x));
	if(t[rt]<val*val+dis*dis)return ;
	if(l==r){t[rt]=val*val+dis*dis;return ;}
	int mid=(l+r)>>1;
	modify(ls,l,mid,x,val);
	modify(rs,mid+1,r,x,val);
	pushup(rt);
}
struct node{
	double fi;
	int se;
	node(double f=0,int s=0){fi=f;se=s;}
}beta[maxn][55];
int sz[maxn];
int up[maxn],down[maxn];
void build2(int rt,int l,int r){
	up[rt]=-1;down[rt]=1e9;t[rt]=inf;
	if(l==r){
		return;
	}
	int mid=(l+r)>>1;
	build2(ls,l,mid);build2(rs,mid+1,r);
}
void modify2(int rt,int l,int r,int x,int y,double val){
	t[rt]=min(t[rt],val);
	up[rt]=max(up[rt],y);
	down[rt]=min(down[rt],y);
	if(l==r){sz[l]++;beta[l][sz[l]]=node(val,y);return ;}
	int mid=(l+r)>>1;
	if(x<=mid)modify2(ls,l,mid,x,y,val);
	else modify2(rs,mid+1,r,x,y,val);
}
double now;
inline void query2(int rt,int l,int r,int x,int y){
	if(up[rt]==-1)return ;
	double dis;
	if(l<=x&&x<=r)dis=0;
	else dis=min(abs(x-l),abs(r-x));
	double dis2;
	if(up[rt]>=y&&y>=down[rt])dis2=0;
	else dis2=min(abs(up[rt]-y),abs(y-down[rt]));
	if(t[rt]+dis*dis+dis2*dis2>=now){
		return ;
	}
	if(l==r){
		double tmp=dis*dis;
		for(register int i=1;i<=sz[l];i++){
			now=min(now,beta[l][i].fi+tmp+(beta[l][i].se-y)*(beta[l][i].se-y));
		}
		return ;
	}
	int mid=(l+r)>>1;
	if(x<=mid){
		query2(ls,l,mid,x,y);
		query2(rs,mid+1,r,x,y);
	}
	else{
		query2(rs,mid+1,r,x,y);
		query2(ls,l,mid,x,y);
	}
}
signed main(){
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	n=read(),k=read();
	int mx=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=k;j++){
			a[i][j]=read();
		}
		mx=max(mx,a[i][1]);
	}
	if(k==2)
	{
		build2(1,0,mx);
		modify2(1,0,mx,0,0,0);
		for(int i=1;i<=n;i++){
			now=inf;
			query2(1,0,mx,a[i][1],a[i][2]);
			dp[i]=sqrt(now);
			modify2(1,0,mx,a[i][1],a[i][2],dp[i]*dp[i]);
			printf("%.4lf\n",dp[i]);
		}
	}
	if(k==1){
		dp[0]=0;
		build(1,0,mx);
		modify(1,0,mx,0,0);
		for(int i=1;i<=n;i++){
			dp[i]=1e18;
			dp[i]=sqrt(t[ps[a[i][1]]]);
			modify(1,0,mx,a[i][1],dp[i]);
		}
		for(int i=1;i<=n;i++){
			printf("%.4lf\n",dp[i]);
		}
	}
	return 0;
}

时间复杂度比较玄学,没有分析。。。

发布了95 篇原创文章 · 获赞 9 · 访问量 3183

猜你喜欢

转载自blog.csdn.net/wmhtxdy/article/details/104479043