魔法逝

无敌の暗黑魔王發表於2024-09-08

原題連結

$\quad $ 先考慮如何處理 \(max(a_p + a_q ,b_p + b_q)\) ,當 \(a_p +a_q \ge b_p +b_q\) 時,\(a_p -b_p \ge b_q -a_q\)

$\quad $ 那我們記法杖的 \(\delta _{p}=a_p -b_p\) ,咒語的 \(\delta_{q}=b_q -a_q\) ,那麼 \(max(a_p + a_q ,b_p + b_q)\) 的取值就只和 \(\delta_{p}\)\(\delta_{q}\) 的大小有關。

$\quad $ 可以發現 \(\delta \in [-2.5 \times 10^5,2.5 \times 10^5]\) ,這個資料範圍建一棵線段樹的話記憶體是可以接受的(當然動態開點最好,但是我學得不好)。
$\quad $ 對於每一個特定的 \(\delta\) ,我們開兩個 \(multiset\) 來分別記錄該點的所有法杖和咒語。
$\quad $ 細節都在註釋裡了。

#define yhl 0
#include<bits/stdc++.h>
using namespace std;
#define ld (x<<1)
#define rd (x<<1|1)
#define IN_MA (1e8)
const int N=1e6+10,res=2.5e5+1;
int m,flag,lan;
struct stu{
    int l,r,a,al,b,bl,ans;
}s[N<<2];
multiset<pair<int,int> >q[N][2];
//只給葉子節點開即可。
inline int min(int x,int y){return x<y?x:y;}
void push_up(int x){
    s[x].ans=min({s[ld].ans,s[rd].ans,s[rd].a+s[ld].al,s[ld].b+s[rd].bl});
    //這裡不僅要算上左右子樹的答案,還要找出跨左右子樹的答案進行更新。
    s[x].a=min(s[ld].a,s[rd].a);
    s[x].al=min(s[ld].al,s[rd].al);
    s[x].b=min(s[ld].b,s[rd].b);
    s[x].bl=min(s[ld].bl,s[rd].bl);
}
void build(int x,int l,int r){
    s[x].l=l,s[x].r=r;
    if(l==r){
        s[x].ans=IN_MA;
        s[x].a=IN_MA;
        s[x].b=IN_MA;
        s[x].al=IN_MA;
        s[x].bl=IN_MA;
        q[s[x].l][yhl].insert(make_pair(IN_MA,IN_MA));
        q[s[x].l][1].insert(make_pair(IN_MA,IN_MA));
        //全初始化成極大值,在兩個set裡插入極大值,這樣就不用判空了。
        return;
    }
    int mid=l+r>>1;
    build(ld,l,mid);
    build(rd,mid+1,r);
    push_up(x);
}
void add(int x,int pos,pair<int,int> op,bool is_a){
    if(s[x].l==s[x].r){
        q[s[x].l][is_a].insert(op);
        if(is_a){
            s[x].a=min(s[x].a,op.first);
            s[x].b=min(s[x].b,op.second);
        }else{
            s[x].al=min(s[x].al,op.first);
            s[x].bl=min(s[x].bl,op.second);
        }
        if(q[s[x].l][is_a].size()&&q[s[x].l][is_a^1].size())
            s[x].ans=(*q[s[x].l][is_a].begin()).first+(*q[s[x].l][is_a^1].begin()).first;
        //在同一位置,對於法杖或咒語來說,a、b之間的差值是一定的,當a最小時,b也最小。
        return;
    }
    int mid=s[x].l+s[x].r>>1;
    if(pos<=mid)add(ld,pos,op,is_a);
    else add(rd,pos,op,is_a);
    push_up(x);
}
void del(int x,int pos,pair<int,int>op,bool is_a){
    if(s[x].l==s[x].r){
        q[s[x].l][is_a].erase(q[s[x].l][is_a].find(op));
        if(is_a){
            s[x].a=(*q[s[x].l][1].begin()).first;
            s[x].b=(*q[s[x].l][1].begin()).second;
        }else{
            s[x].al=s[x].bl=IN_MA;
            s[x].al=(*q[s[x].l][yhl].begin()).first;
            s[x].bl=(*q[s[x].l][yhl].begin()).second;
        }
        s[x].ans=(*q[s[x].l][is_a].begin()).first+(*q[s[x].l][is_a^1].begin()).first;
        return;
    }
    int mid=s[x].l+s[x].r>>1;
    if(pos<=mid)del(ld,pos,op,is_a);
    else del(rd,pos,op,is_a);
    push_up(x);
}
int main(){
    scanf("%d%d",&m,&flag);
    build(1,1,500001);
    //偏移量最小設定為2.5e5+1。
    while(m--){
        int op,fl,a,b;
        scanf("%d%d%d%d",&op,&fl,&a,&b);
        if(flag)a^=lan,b^=lan;
        if(op==1){
            if(fl)add(1,res+b-a,make_pair(a,b),yhl);
            else add(1,res+a-b,make_pair(a,b),1);
        }else{
            if(fl)del(1,res+b-a,make_pair(a,b),yhl);
            else del(1,res+a-b,make_pair(a,b),1);
        }
        lan=s[1].ans>=1e8?yhl:s[1].ans;;
        printf("%d\n",lan);
    }
    return yhl;
}

相關文章