The Kouga Ninja Scrolls(2018瀋陽現場E+切比雪夫距離+線段樹維護最大次大最小次小)

The Kouga Ninja Scrolls

這題可真暴力呀!曼哈頓距離轉成切比雪夫距離後大力線段樹搞即可!第一次把線段樹封裝一下,爲了x,yx,y兩個座標不用寫兩棵線段樹,也是第一次把pushpush_upup寫成結構體mergemerge形式,爲了方便query時的區間合併。而且寫好後(賽後)1A,刺激!!!

題意

給定二維平面上nn個點(編號11~nn),以及每個點的顏色(幫派),三種操作:

  1. op1:op1:將第ii個點的移動到另一個位置
  2. op2:op2:改變第ii個點的顏色(幫派)
  3. op3:op3:詢問編號屬於[l,r][l,r]的點中曼哈頓距離的最大值(要求選定最遠點對顏色不同)

思路

  1. 看見曼哈頓距離最大值,儘可能往切比雪夫距離上面想。比如這題,將距離轉化後,我們只需要分別考慮xx距離最大值和yy距離最大值即可;
  2. 然後就是如何分別求這兩個最大距離,容易想到利用座標的區間最大值和區間最小值,相減即是區間最大值啦!
  3. 但題目有個限制,也就是大幅度增加此題碼量的地方!最大距離點對顏色不能相同,那就只能再分別維護一個座標次大值和座標次小值(且顏色要與最大次大不同),這樣當最大最小的兩個點顏色相同時,就把其中一個換成次一點的。
  4. 那麼,思路就是如此了,代碼碼起來也是異常舒服!

代碼

#include "bits/stdc++.h"
#define hhh printf("hhh\n")
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline ll read() {ll x=0,f=1;char c=getchar();while(c!='-'&&(c<'0'||c>'9'))c=getchar();if(c=='-')f=-1,c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return f*x;}

const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const double eps = 1e-7;

int n, m;
ll x[maxn], y[maxn], belong[maxn];

struct P{
    ll m[4]; int b[4];
    void clear() {
        memset(m,0,sizeof(m));
        memset(b,0,sizeof(b));
    }
    P() { clear(); }
    friend P merge(const P &c, P const &b) {//第一次寫成結構體合併的形式,真的舒服
        P a=c;
        if(b.b[0]) {
            if(!a.b[0]||b.m[0]>=a.m[0]) {
                if(!a.b[0]) a.m[0]=b.m[0], a.b[0]=b.b[0];
                else if(b.b[0]!=a.b[0]) {
                    swap(a.m[0],a.m[1]); swap(a.b[0],a.b[1]);
                    a.m[0]=b.m[0], a.b[0]=b.b[0];
                }
                else if(b.m[0]>a.m[0]) a.m[0]=b.m[0];
            }
            else if(b.b[0]!=a.b[0]&&(!a.b[1]||b.m[0]>a.m[1])) {
                a.m[1]=b.m[0], a.b[1]=b.b[0];
            }
        }
        if(b.b[1]) {
            if(!a.b[0]||b.m[1]>=a.m[0]) {
                if(!a.b[0]) a.m[0]=b.m[1], a.b[0]=b.b[1];
                else if(b.b[1]!=a.b[0]) {
                    swap(a.m[0],a.m[1]); swap(a.b[0],a.b[1]);
                    a.m[0]=b.m[1], a.b[0]=b.b[1];
                }
                else if(b.m[1]>a.m[0]) a.m[0]=b.m[1];
            }
            else if(b.b[1]!=a.b[0]&&(!a.b[1]||b.m[1]>a.m[1])) {
                a.m[1]=b.m[1], a.b[1]=b.b[1];
            }
        }
        if(b.b[3]) {
            if(!a.b[3]||b.m[3]<=a.m[3]) {
                if(!a.b[3]) a.m[3]=b.m[3], a.b[3]=b.b[3];
                else if(b.b[3]!=a.b[3]) {
                    swap(a.m[3],a.m[2]); swap(a.b[3],a.b[2]);
                    a.m[3]=b.m[3], a.b[3]=b.b[3];
                }
                else if(b.m[3]<a.m[3]) a.m[3]=b.m[3];
            }
            else if(b.b[3]!=a.b[3]&&(!a.b[2]||b.m[3]<a.m[2])) {
                a.m[2]=b.m[3], a.b[2]=b.b[3];
            }
        }
        if(b.b[2]) {
            if(!a.b[3]||b.m[2]<=a.m[3]) {
                if(!a.b[3]) a.m[3]=b.m[2], a.b[3]=b.b[2];
                else if(b.b[2]!=a.b[3]) {
                    swap(a.m[3],a.m[2]); swap(a.b[3],a.b[2]);
                    a.m[3]=b.m[2], a.b[3]=b.b[2];
                }
                else if(b.m[2]<a.m[3]) a.m[3]=b.m[2];
            }
            else if(b.b[2]!=a.b[3]&&(!a.b[2]||b.m[2]<a.m[2])) {
                a.m[2]=b.m[2], a.b[2]=b.b[2];
            }
        }
        return a;
    }
};

struct SegmentTree{//第一次把線段樹給封裝了,也是真的舒服!!!
    P node[maxn<<2];

    void build(int l, int r, int now) {
        node[now].clear();
        if(l==r) return;
        int m=(l+r)/2;
        build(l,m,now<<1); build(m+1,r,now<<1|1);
    }

    void update(int x, ll d, int l, int r, int now) {
        if(l==r) {
            node[now].m[0]=node[now].m[3]=d;
            node[now].b[0]=node[now].b[3]=belong[x];
            return;
        }
        int m=(l+r)/2;
        if(x<=m) update(x,d,l,m,now<<1);
        else update(x,d,m+1,r,now<<1|1);
        node[now]=merge(node[now<<1],node[now<<1|1]);
    }

    P query(int x, int y, int l, int r, int now) {
        if(x<=l&&r<=y) return node[now];
        int m=(l+r)/2;
        P ans;
        if(x<=m) ans=merge(ans,query(x,y,l,m,now<<1));
        if(y>m) ans=merge(ans,query(x,y,m+1,r,now<<1|1));
        return ans;
    }

    ll solve(int x, int y) {
        P ans=query(x,y,1,n,1);
        ll res=-2e18;
        if(!ans.b[0]||!ans.b[3]) return 0;
        if(ans.b[0]==ans.b[3]) {
            if(ans.b[2]) res=max(res,ans.m[0]-ans.m[2]);
            if(ans.b[1]) res=max(res,ans.m[1]-ans.m[3]);
        }
        else res=ans.m[0]-ans.m[3];
        if(res<-1e18) return 0;
        return res;
    }
}sx, sy;

int main() {
    int T=read(); int t=0;
    while(T--) {
        printf("Case #%d:\n", ++t);
        n=read(), m=read();
        sx.build(1,n,1); sy.build(1,n,1);
        for(int i=1; i<=n; ++i) {
            ll x=read(), y=read(); belong[i]=read();
            ::x[i]=x+y, ::y[i]=x-y;
            sx.update(i,::x[i],1,n,1);
            sy.update(i,::y[i],1,n,1);
        }
        for(int i=1; i<=m; ++i) {
            int op=read();
            if(op==1) {
                int k=read(); ll dx=read(), dy=read();
                x[k]+=dx+dy; y[k]+=dx-dy;
                sx.update(k,x[k],1,n,1);
                sy.update(k,y[k],1,n,1);
            }
            else if(op==2) {
                int k=read(), c=read();
                belong[k]=c;
                sx.update(k,x[k],1,n,1);
                sy.update(k,y[k],1,n,1);
            }
            else if(op==3) {
                int l=read(), r=read();
                printf("%lld\n", max(sx.solve(l,r),sy.solve(l,r)));
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章