2018-2019 ACM-ICPC, Asia Shenyang Regional Contest E. The Kouga Ninja Scrolls 切比雪夫距离 +线段树

在这里插入图片描述
传送门
将曼哈顿距离转换成切比雪夫距离,现在就是求 m a x ( ∣ x 1 − x 2 ∣ , ∣ y 1 − y 2 ∣ ) max(|x_1-x_2|,|y_1-y_2|) max(x1x2,y1y2),显然我们可以将 x , y x,y x,y分开考虑,下面以 x x x为例。

考虑一段区间内不同门派的最大值和最小值,我们可以维护这个区间的最大值和最小值,以及与最大值门派不同的次大值和与最小值门派不同的次小值,这样就不难得出答案了。

#include<bits/stdc++.h>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define pb push_back
using namespace std;

const int N=1000010,INF=0x3f3f3f3f,mod=1e9+7;
typedef long long LL;

int n,m;
int a[N],x[N],y[N],z[N];

/*
最大值  与最大值门派不同的次大值
最小值  与最小值门派不同的次小值
*/
struct Point {
    LL val,id;
};
vector<Point>v;

bool cmp1(Point a,Point b) {
    return a.val>b.val;
}

bool cmp2(Point a,Point b) {
    return a.val<b.val;
}

struct Seg {
    struct Node {
        int l,r;
        LL maxid[2],minid[2];
        LL maxval[2],minval[2];
    }tr[N<<2];

    void update(Node &u,Node ls,Node rs) {
        //最大值
        if(ls.maxval[0]>rs.maxval[0]) swap(ls,rs);
        u.maxval[0]=rs.maxval[0];
        u.maxid[0]=rs.maxid[0];
        //次大值
        v.clear();
        v.push_back({ls.maxval[0],ls.maxid[0]});
        v.push_back({ls.maxval[1],ls.maxid[1]});
        v.push_back({rs.maxval[1],rs.maxid[1]});
        sort(v.begin(),v.end(),cmp1);
        u.maxval[1]=-1e9-1;
        u.maxid[1]=0;
        for(auto x:v) if(x.id!=u.maxid[0]&&x.id!=0) {
            u.maxval[1]=x.val;
            u.maxid[1]=x.id;
            break;
        }

        //最小值
        if(ls.minval[0]<rs.minval[0]) swap(ls,rs);
        u.minval[0]=rs.minval[0];
        u.minid[0]=rs.minid[0];
        //次小值
        v.clear();
        v.push_back({ls.minval[0],ls.minid[0]});
        v.push_back({ls.minval[1],ls.minid[1]});
        v.push_back({rs.minval[1],rs.minid[1]});
        sort(v.begin(),v.end(),cmp2);
        u.minval[1]=1e9+1;
        u.minid[1]=0;
        for(auto x:v) if(x.id!=u.minid[0]&&x.id!=0) {
            u.minval[1]=x.val;
            u.minid[1]=x.id;
            break;
        }
    }

    void pushup(int u) {
        update(tr[u],tr[L],tr[R]);
    }

    void build(int u,int l,int r) {
        tr[u]={l,r};
        if(l==r) {
            tr[u].maxid[0]=tr[u].minid[0]=z[l];
            tr[u].maxid[1]=tr[u].minid[1]=0;
            tr[u].maxval[0]=tr[u].minval[0]=a[l];
            tr[u].maxval[1]=-1e9-1;
            tr[u].minval[1]=1e9+1;
            return;
        }
        build(L,l,Mid); build(R,Mid+1,r);
        pushup(u);
    }

    void change_val(int u,int pos,int val) {
        if(tr[u].l==tr[u].r) {
            tr[u].maxval[0]+=val;
            tr[u].minval[0]+=val;
            return;
        }
        if(pos<=Mid) change_val(L,pos,val);
        else change_val(R,pos,val);
        pushup(u);
    }

    void change_id(int u,int pos,int val) {
        if(tr[u].l==tr[u].r) {
            tr[u].maxid[0]=val;
            tr[u].minid[0]=val;
            return;
        }
        if(pos<=Mid) change_id(L,pos,val);
        else change_id(R,pos,val);
        pushup(u);
    }

    Node query(int u,int l,int r) {
        if(tr[u].l>=l&&tr[u].r<=r) return tr[u];
        if(r<=Mid) return query(L,l,r);
        else if(l>Mid) return query(R,l,r);
        else {
            Node ans,ls,rs;
            ls=query(L,l,r); rs=query(R,l,r);
            update(ans,ls,rs);
            return ans;
        }
    }

    LL get_ans(int l,int r) {
        Node u=query(1,l,r);
        LL ans=0;
        for(int i=0;i<2;i++) {
            for(int j=0;j<2;j++) {
                if(u.maxid[i]!=u.minid[j]&&u.maxid[i]!=0&&u.minid[j]!=0) {
                    ans=max(ans,abs(u.maxval[i]-u.minval[j]));
                }
            }
        }
        return ans;
    }
}seg[2];

void solve() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d%d%d",&x[i],&y[i],&z[i]);
    for(int i=1;i<=n;i++) a[i]=x[i]+y[i];
    seg[0].build(1,1,n);
    for(int i=1;i<=n;i++) a[i]=x[i]-y[i];
    seg[1].build(1,1,n);
    while(m--) {
        int op; scanf("%d",&op);
        if(op==1) {
            int k,x,y;
            scanf("%d%d%d",&k,&x,&y);
            seg[0].change_val(1,k,x+y);
            seg[1].change_val(1,k,x-y);
        } else if(op==2) {
            int k,c;
            scanf("%d%d",&k,&c);
            seg[0].change_id(1,k,c);
            seg[1].change_id(1,k,c);
        } else {
            int l,r; scanf("%d%d",&l,&r);
            printf("%lld\n",max(seg[0].get_ans(l,r),seg[1].get_ans(l,r)));
        }
    }
}

int main() {
	int _; scanf("%d",&_);
	for(int i=1;i<=_;i++) {
        printf("Case #%d:\n",i);
		solve();
	}

    return 0;
}
/*
1
2 1
1 1 1
1 1 2
3 1 2

6 2
hahaha
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值