• 不可视境界线


    前言

    总之就是很离谱。

    题目

    USOJ

    \(1\le n\le 10^5;1\le k\le 2;\) 坐标范围在 \([0,10^4)\) 之间。

    讲解

    题目中的式子长得就很像距离,维护 \(dp_i\) 表示前 \(i\) 个的总伤害,把根号内看成单次伤害,发现转移的时候能把后面的 \(-a\) 抵消掉。

    又有 \(k\) 维,所以我们直接上K-D树,将 \(k\) 维坐标转换为 \(k+1\) 维,前面一维加一个dp值来方便,为了避免过多开方而导致常数过大,所以我第一个值用的曼哈顿距离,不用平方。

    代码

    //12252024832524
    #include <bits/stdc++.h>
    #define TT template<typename T>
    using namespace std; 
    
    typedef long long LL;
    const int MAXN = 100005;
    const double alpha = 0.65;
    const LL INF = 1ll << 60;
    int n,k,rb[MAXN];
    int nxt[3] = {1,2,0};
    
    LL Read()
    {
    	LL x = 0,f = 1;char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x); if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    int tot,rt,mode;
    struct point{LL x[3];}tmp[MAXN];
    bool operator < (point A,point B){return A.x[mode] < B.x[mode];}
    #define lc t[x].ch[0]
    #define rc t[x].ch[1]
    struct node{point p,l,r;int ch[2],fa,siz,md;}t[MAXN];
    LL sq(LL x){return x*x;}
    LL dis(point A,point B)
    {
    	LL ret = Abs(A.x[0]-B.x[0]);
    	for(int i = 1;i < k;++ i) ret += sq(A.x[i]-B.x[i]);
    	return ret;
    }
    int newnode(){int x = rb[++tot];lc = rc = t[x].fa = 0;return x;}
    void up1(int x,int son)
    {
    	if(!son) return;
    	for(int i = 0;i < k;++ i)
    		t[x].l.x[i] = Min(t[x].l.x[i],t[son].l.x[i]),t[x].r.x[i] = Max(t[x].r.x[i],t[son].r.x[i]);
    	t[x].siz += t[son].siz;
    }
    void up(int x)
    {
    	t[x].l = t[x].r = t[x].p; t[x].siz = 1;
    	up1(x,lc); up1(x,rc);
    }
    bool wc(int x){return x == t[t[x].fa].ch[1];}//which child :)
    void Build(int &x,int l,int r,int now)
    {
    	x = newnode(); mode = now;
    	int mid = (l+r) >> 1;
    	nth_element(tmp+l,tmp+mid,tmp+r+1);
    	t[x].p = tmp[mid]; t[x].md = now;
    	if(l < mid) Build(lc,l,mid-1,nxt[now]),t[lc].fa = x;
    	if(mid < r) Build(rc,mid+1,r,nxt[now]),t[rc].fa = x;
    	up(x);
    }
    int nd,cur;
    void dfs(int x)
    {
    	tmp[++cur] = t[rb[tot--] = x].p;
    	if(lc) dfs(lc);
    	if(rc) dfs(rc);
    }
    void pia(int x)
    {
    	cur = 0; dfs(x);
    	if(t[x].fa) Build(t[t[x].fa].ch[wc(x)],1,cur,t[x].md);
    	else Build(rt,1,cur,t[x].md);
    }
    point pp;
    void ins(int &x,int now)
    {
    	if(x == rt) nd = 0;
    	if(!x)
    	{
    		x = newnode();
    		t[x].p = pp;
    		t[x].md = now;
    		up(x);
    		return;
    	}
    	mode = now;
    	if(pp < t[x].p) ins(lc,nxt[now]),t[lc].fa = x;
    	else ins(rc,nxt[now]),t[rc].fa = x;
    	up(x);
    	if(Max(t[lc].siz,t[rc].siz) > t[x].siz * alpha) nd = x;
    	if(x == rt && nd) pia(nd);
    }
    LL ans;
    LL closest(int x,point p)
    {
    	LL ret = 0,dz;
    	for(int i = 0;i < k;++ i)
    	{
    		dz = 0;
    		if(p.x[i] < t[x].l.x[i]) dz = t[x].l.x[i]-p.x[i];
    		else if(p.x[i] > t[x].r.x[i]) dz = p.x[i]-t[x].r.x[i];
    		if(!i) ret += dz;
    		else ret += sq(dz);
    	}
    	return ret;
    }
    void Query(int x)
    {
    	if(closest(x,pp) >= ans) return;
    	ans = Min(ans,dis(t[x].p,pp));
    	if(lc && rc)
    	{
    		if(closest(lc,pp) < closest(rc,pp)) Query(lc),Query(rc);
    		else Query(rc),Query(lc);
    	}
    	else
    	{
    		if(lc) Query(lc);
    		if(rc) Query(rc);
    	}
    }
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	n = Read(); k = Read()+1; 
    	for(int i = 1;i <= n+1;++ i) rb[i] = i;
    	if(k == 2) nxt[1] = 0;
    	pp = point{0,0,0}; ins(rt,0);
    	for(int i = 1;i <= n;++ i)
    	{
    		pp = point{0,0,0}; ans = INF;
    		for(int j = 1;j < k;++ j) pp.x[j] = Read();
    		Query(rt);
    		pp.x[0] = ans; ins(rt,0);
    		printf("%.4f\n",sqrt(ans));
    	}
    	return 0;
    }
    

    后记

    有趣的是因为这道题没有来源,是我们内部造的数据,所以我先写了一发暴力(无替罪羊式重构),最大跑了1.9s。此时的时限是1s。

    后来改成有重构版本,竟然要跑16s+,我直接震撼,后来把平衡因子从0.69改成了0.99才跑过。(???)

    当然最后发现是写错了,大概就是如果发现有某个点不平衡,重构整棵树。改了就过了。

    于是我加了两组卡0.99那个版本的数据,然后我的正解竟然也过不了,被迫把时限开成2s。

    然后网上的标程T了,我的0.99错误版本偶尔还能过。

  • 相关阅读:
    HTML--1标签表格
    HTML--4格式布局
    HTML--3css样式表
    快速制作网页的方法
    表单
    表单练习——邮箱注册
    斐波那契数列
    0125 多线程 继承Thread 练习
    Hash(哈希)
    [COI2007] [luogu P1823] Patrik 音乐会的等待 解题报告 (单调栈)
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/15876757.html
Copyright © 2020-2023  润新知