题意 :
- 商店里面有n个种类宝石,分别给出第一次购买和第二次购买的价格,只有购买完第一次后才能用第二次购买的价格,两人都想用最少的成本购买宝石
- 购买的顺序是 : 爱丽丝先买一块石英,然后鲍勃和爱丽丝轮流买两块,直到只剩下一块。以A代表Alice,B代表Bob,顺序为ABBAA...BBA
- 然后m次修改操作,修改某一种类宝石第一次购买和第二次购买的价格,每轮修改后输出爱丽丝的最小花费
题解思路 :
假设Alice全以第一次的价格购买n种宝石(显然这是不可能的),对于a[i]<=b[i]的宝石,Alice是赚的,否则Alice是亏的。双方开始轮流选宝石,一开始肯定是选最赚的(也就是(a[i]-b[i]为负数且越小越好))的第一次价格,并且根据赚的程度依次由ABBAABB...挑走。
选完所有赚的宝石,为了避免选到亏的宝石,Alice和Bob会回头去以第二次价格选对方选过的。
我们模拟一遍过程可知,假如赚的宝石数量为奇数,那么亏的宝石一定由Bob开始选第一个,并且根据亏的程度由BABABABA...挑走;假如赚的宝石数量为偶数,那么亏的宝石一定由Alice开始选第一个,并且根据亏的程度由ABABABAB...挑走。
如何求第1,3,5,7....大的数的总和呢?我们可以用权值线段树来维护。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define lson pos<<1
#define rson pos<<1|1
const int N=3e5+10;
const int maxn=1e5;
int n,m;
int a[N],b[N];
//int tree[N<<3];
struct node {
int sum[4];
int size;
} tree[N<<3];
void pushup(int pos) {
tree[pos].size=tree[lson].size+tree[rson].size;
for(int i=0; i<4; i++) {
tree[pos].sum[i]=tree[lson].sum[i];
}
int ave=tree[lson].size%4;
for(int i=0; i<4; i++) {
tree[pos].sum[(i+ave)%4]+=tree[rson].sum[i];
}
}
void update(int pos, int l, int r, int k, int cnt) { //表示数k的个数多cnt个
if(l==r) {
if(cnt==1) {
int x = tree[pos].size % 4 ;
tree[pos].sum[x]+=cnt*k;
tree[pos].size++;
} else {
int x = (tree[pos].size-1)%4;
tree[pos].sum[x]+=cnt*k;
tree[pos].size--;
}
// tree[pos].size+=cnt;
return;
}
int mid=(l+r)>>1;
if(k<=mid) update(lson,l,mid,k,cnt);
else update(rson,mid+1,r,k,cnt);
pushup(pos);
}
int ans,temp;
int get() {
int res=tree[1<<1].sum[1]+tree[1<<1].sum[2];
temp=ans;
ans-=res;
if(tree[2].size%2) { //奇数
ans-=tree[3].sum[0]+tree[3].sum[2];
} else {
ans-=tree[3].sum[1]+tree[3].sum[3];
}
cout<<ans<<'\n';
ans=temp;
}
void solve() {
cin>>n>>m;
for(int i=1; i<=n; i++) {
cin>>a[i]>>b[i];
update(1,-maxn,maxn,a[i]-b[i],1);
ans+=a[i];
}
get();
for(int i=1,x,y,z; i<=m; i++) {
cin>>x>>y>>z;
update(1,-maxn,maxn,a[x]-b[x],-1);
ans-=a[x];
a[x]=y; b[x]=z;
update(1,-maxn,maxn,y-z,1);
ans+=a[x];
get();
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--)solve();
return 0;
}