原題連結
$\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;
}