[Luogu4169] [Violet]天使玩偶/SJY擺棋子 [cdq分治/k-d tree]

[Link\frak{Link}]


考慮用 cdq 分治解決?
顯然依舊分成修改跟查詢,考慮一維排序二維cdq?啊但是那顯然不太對,cdq能解決三維偏序,
但是她不能解決最近點對啊。平面最近點對並不能這麼幹。
那我們考慮一點別噠。怎麼把題目給出的問題轉化成三維偏序?
“最近”點對就有一種偏序的感覺,但是怎麼轉化呢?
感覺很不好搞?
但是呢,但是呢,如果變成單純的比較 x y 座標大小,就很好做了呀?
因爲是偏序問題,所以實際上也不好直接這麼搞
比如說我們只考慮第三象限
如果簡單考慮,對詢問 (x,y)(x,y) 直接求 xix,yiyx_i\le x,y_i\le y 點中 min(xix+yiy)\min{(x_i-x+y_i-y)}
這樣對詢問的依賴就比較大,
所以我們換一下思路,去掉 xxyy 那麼
對詢問 (x,y)(x,y) 只需要求 xix,yiyx_i\le x,y_i\le y 點中 max(xi+yi)\max{(x_i+y_i)}
問題就被簡化辣。
一維時間,二維橫座標,三維縱座標


彳巴
那麼只需要把曼哈頓距離拆開變成四個方向(四個象限)就不難搞了errrr
簡單吧?(xxx
你可能會說,四個方向搞你馬呢
這樣,我們換一次方向就把整個圖轉一遍?
然後cdq的時候只處理在固定方向上的點。


cdq 的話,實際上還可以多加一個優化,就是把一開始的 nn 個點提出來單獨處理。
但是我沒有寫x


kk-d tree 的話就是一個裸題了
複雜度:建樹 best case O(nlogn)O(n\log n) ,worst case O(knlogn)O(kn\log n)
空間複雜度 O(2n)O(2n)
插入 O(logn)O(\log n) 刪除 O(logn)O(\log n)
求最近鄰 O(nlogn)O(n\log n) in average ,worst case O(n2)O(n^2)
數點 worst case O(knk1k)O(k\sqrt[k]{n^{k-1}})

注意,高維空間中,一般 n2kn\gg2^k 的時候用 kk-d tree 找最近鄰效果纔會好一點;
實際上維度很高的時候,假如點數不多,求最近鄰甚至不如用窮舉
另外也有近似算法 利用 p\ell_p


cdq
#include<cstdio>
#include<cmath>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline void setmax(int&a,const int&b)
{
    if(a<b)a=b;
}
inline void setmin(int&a,const int&b)
{
    if(a>b)a=b;
}
#define getchar() (frS==frT&&(frT=(frS=frBB)+fread(frBB,1,1<<12,stdin),frS==frT)?EOF:*frS++)
char frBB[1<<12], *frS=frBB, *frT=frBB;
int read()
{
    char ch = getchar(); bool w = 0; int x = 0;
    while (!isdigit(ch)) w |= (ch == '-'), ch = getchar();
    while (isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar();
    return w ? -x : x;
}
const int MAXN = 600005;
const int INF = 0x3f3f3f3f;
int n, m, u;
struct pt
{
    int x;
    int y;
    int id;
    pt(int b=0, int c=0, int d=0)
    {
        x = b;
        y = c;
        id = d;
    }
    bool operator < (const pt& o) const
    {
        return x <= o.x;
    }
}o[MAXN], e[MAXN], sav[MAXN];
int x[MAXN], y[MAXN], tem[MAXN], met[MAXN], bit[1000005], ans[MAXN];
int p, q, tot, r, s;
void Modify(int x, int k)
{
    while(x<=s)
    {
        setmax(bit[x], k);
        x += x & -x;
    }
}
void Clear(int x)
{
    while (x<=s)
    {
        if(bit[x])bit[x]=0;
        else break;
        x += x & -x;
    }
}
int Query(int x)
{
    int ret = 0;
    while(x)
    {
        setmax(ret, bit[x]);
        x -= x & -x;
    }
    return ret;
}
int f;
void cdq(int L, int R)
{
    if (L == R) return;
    int Mid = L + R >> 1;
    cdq(L, Mid);
    cdq(Mid + 1, R);
    for (p = L, q = Mid + 1; q <= R; ++q)
    {
        if (o[q].id)
        {
            for (; p <= Mid && o[p].x <= o[q].x; ++p)
            {
                if (!o[p].id) Modify(o[p].y, o[p].x+o[p].y);
            }
            f = Query(o[q].y);
            if(f) setmin(ans[o[q].id],o[q].x+o[q].y-f);
        }
    }
    for (int i = L; i <= p; ++i) if (!o[i].id) Clear(o[i].y);
    merge(o+L, o+Mid+1, o+Mid+1, o+R+1, e+L);
    for (int i = L; i <= R; ++i) o[i] = e[i];
}
int rx, ry, rt;
void Del()
{
    rx=ry=rt=0;
    for (register int i=1;i<=m;++i)if(o[i].id)setmax(rx,o[i].x),setmax(ry,o[i].y);
    for (register int i=1;i<=m;++i)if(o[i].x<=rx&&o[i].y<=ry)e[++rt]=o[i];
    memcpy(o,e,sizeof(e));
}
int main()
{
    n = read(); m = read();
    
    register int *xwhere = x+1, *ywhere = y+1;
    for (register int i = 1; i <= n; ++i)
    {
        (*xwhere) = 1+read(), (*ywhere) = 1+read();
        setmax(r,*xwhere); setmax(s,*ywhere);
        o[i] = pt(*(xwhere++), *(ywhere++));
        
    }
    
    m += n;
    for (register int t, i = n + 1; i <= m; ++i)
    {
        t = read();
        (*xwhere) = 1+read(), (*ywhere) = 1+read();
        setmax(r,*xwhere); setmax(s,*ywhere);
        o[i] = pt(*(xwhere++), *(ywhere++), (t==2)?(++u):0);
    }
    
    ++r; ++s;
    memcpy(sav,o,sizeof(o));
    for (int i = 1; i <= u; ++i) ans[i] = INF;
    Del();cdq(1,rt);
    
    memcpy(o,sav,sizeof(sav));
    for (int i = 1; i <= m; ++i) o[i].x = r-o[i].x;
    Del();cdq(1,rt);
    
    memcpy(o,sav,sizeof(sav));
    for (int i = 1; i <= m; ++i) o[i].y = s-o[i].y;
    Del();cdq(1,rt);
    
    memcpy(o,sav,sizeof(sav));
    for (int i = 1; i <= m; ++i) o[i].x = r-o[i].x, o[i].y=s-o[i].y;
    Del();cdq(1,rt);
    
    for (int i = 1; i <= u; ++i) printf("%d\n", ans[i]);
    return 0;
}

kdt
把我調炸了。。。
#include<cstdio>
#include<cmath>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define getchar() (frS==frT&&(frT=(frS=frBB)+fread(frBB,1,1<<12,stdin),frS==frT)?EOF:*frS++)
char frBB[1<<12], *frS=frBB, *frT=frBB;
int read()
{
    char ch = getchar(); int x = 0; bool w = 0;
    while (!isdigit(ch)) w |= (ch == '-'), ch = getchar();
    while (isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar();
    return w ? -x : x;
}
#define max(DefVa,DefVb) ((DefVa)>(DefVb)?(DefVa):(DefVb))
#define min(DefVa,DefVb) ((DefVa)<(DefVb)?(DefVa):(DefVb))
#define setmax(DefVa,DefVb) ((DefVb)>(DefVa)?((DefVa)=(DefVb)):0)
#define setmin(DefVa,DefVb) ((DefVb)<(DefVa)?((DefVa)=(DefVb)):0)
#define abs(x) ((x)<0?(-(x)):(x))
const double Alph = 0.75;
const int INF = 0x3f3f3f3f;
const int MAXN = 1000005;
int n, m, Root, cd;
struct pt
{
    int x, y;
    pt(int xx=0, int yy=0)
    {
        x = xx;
        y = yy;
    }
}TemStack[MAXN], CorPt[MAXN];
int TemStackTot;
int Child[MAXN][2];
int Siz[MAXN];
int Xmn[MAXN], Xmx[MAXN], Ymn[MAXN], Ymx[MAXN];
int CorId[MAXN];
int Dim[MAXN];
int Rec[MAXN], top, Ntot;
#define NewNode() (top?Rec[top--]:++Ntot)
#define LChild(DefVal) Child[DefVal][0]
#define RChild(DefVal) Child[DefVal][1]
inline bool cmpx(const pt& a, const pt& b) { return a.x < b.x;}
inline bool cmpy(const pt& a, const pt& b) { return a.y < b.y;}
inline void Maintain(const int& x)
{
    static int l, r;
    l = LChild(x);
    r = RChild(x);
    
    Siz[x] = Siz[l] + Siz[r] + 1;
    Xmn[x] = Xmx[x] = CorPt[x].x;
    Ymn[x] = Ymx[x] = CorPt[x].y;
    
    if (l)
    {
        setmin(Xmn[x], Xmn[l]);
        setmin(Ymn[x], Ymn[l]);
        setmax(Xmx[x], Xmx[l]);
        setmax(Ymx[x], Ymx[l]);
    }
    
    if (r)
    {
        setmin(Xmn[x], Xmn[r]);
        setmin(Ymn[x], Ymn[r]);
        setmax(Xmx[x], Xmx[r]);
        setmax(Ymx[x], Ymx[r]);
    }
    
}
int Structure(int L, int R)
{
    if (L > R) return 0;
    
    if (L == R)
    {
    	CorId[L] = NewNode();
        Dim[CorId[L]] = 0;
        CorPt[CorId[L]] = TemStack[L];
        Maintain(CorId[L]);
        return CorId[L];
    }
    
    
    static int XMn, XMx, YMn, YMx;
    
    XMn = INF, XMx = 0, YMn = INF, YMx = 0;
    
    for (register int i = L; i <= R; ++i)
    {
        setmax(XMx, TemStack[i].x);
        setmin(XMn, TemStack[i].x);
        setmax(YMx, TemStack[i].y);
        setmin(YMn, TemStack[i].y);
    }
    
    
    int Mid = L + R >> 1;
    CorId[Mid] = NewNode();
    
    (XMx-XMn>=YMx-YMn)?
    (nth_element(TemStack + L, TemStack + Mid + 1, TemStack + R + 1, cmpx), Dim[CorId[Mid]] = 0):
    (nth_element(TemStack + L, TemStack + Mid + 1, TemStack + R + 1, cmpy), Dim[CorId[Mid]] = 1);
    
    CorPt[CorId[Mid]] = TemStack[Mid];
    
    LChild(CorId[Mid]) = Structure(L, Mid - 1);
    RChild(CorId[Mid]) = Structure(Mid + 1, R);
    
    Maintain(CorId[Mid]);
    return CorId[Mid];
    
}
int temN;
void Destroy(int x)
{
    if(LChild(x)) Destroy(LChild(x)), LChild(x) = 0;
    
    TemStack[++TemStackTot] = CorPt[x];
    CorId[TemStackTot] = x;
    Rec[++top] = x;
    
    if(RChild(x)) Destroy(RChild(x)), RChild(x) = 0;
}
void Insert(const int& x, const int& y)
{
    register int Pos = Root, Fa = 0;
    register bool Belong;
    
    while(Pos)
    {
        setmax(Xmx[Pos], x);
        setmin(Xmn[Pos], x);
        setmax(Ymx[Pos], y);
        setmin(Ymn[Pos], y);
        
        ++Siz[Pos];
        
        
        Belong = !(Dim[Pos]?(y<=CorPt[Pos].y):(x<=CorPt[Pos].x));
        
        if (!Child[Pos][Belong])
        {
            Child[Pos][Belong] = temN = NewNode();
            CorPt[temN] = pt(x,y); Maintain(temN); 
            return;
        }
        else if (Siz[Child[Pos][Belong]] + 1 > Siz[Pos] * Alph)
        {
            TemStackTot = 0; Destroy(Pos);
            TemStack[++TemStackTot] = pt(x,y);
            CorId[TemStackTot] = NewNode();
            if (Pos != Root) Child[Fa][Pos==RChild(Fa)] = Structure(1, TemStackTot), Maintain(Fa);
            else Root = Structure(1, TemStackTot);
            return;
        }
        else
        {
            Fa = Pos;
            Pos = Child[Pos][Belong];
        }
    }
}
inline int CalcDist(int p, int x, int y)
{
    return max(0,x-Xmx[p])+max(0,Xmn[p]-x)+max(0,y-Ymx[p])+max(0,Ymn[p]-y);
}
int Ans;
inline void Query(int Pos, const int& x, const int& y)
{
    setmin(Ans, abs(CorPt[Pos].x - x) + abs(CorPt[Pos].y - y));
    int DisL = LChild(Pos)?CalcDist(LChild(Pos), x, y):INF;
    int DisR = RChild(Pos)?CalcDist(RChild(Pos), x, y):INF;
    if(DisL < DisR)
    {
        if (DisL < Ans) Query(LChild(Pos), x, y);
        if (DisR < Ans) Query(RChild(Pos), x, y);
    }
    else
    {
        if (DisR < Ans) Query(RChild(Pos), x, y);
        if (DisL < Ans) Query(LChild(Pos), x, y);
    }
}
int main()
{
    n = read(), m = read();
    for (register int i = 1; i <= n; ++i) TemStack[i].x=read(), TemStack[i].y=read();
    
    TemStackTot = n;
    Root = Structure(1, n);
    TemStackTot = 0;
    
    for (register int t, x, y, i = 1; i <= m; ++i)
    {
        t=read(); x=read(); y=read();
        if (t&1) Insert(x, y);
        else Ans = INF, Query(Root, x, y), printf("%d\n", Ans);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章