QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#154528 | #5441. Quartz Collection | value0 | RE | 0ms | 0kb | C++20 | 3.6kb | 2023-08-31 18:47:44 | 2023-08-31 18:47:45 |
answer
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
ll n,m;
const int N = 1e5 + 10;
//我们是以a[i]-b[i]为基础进行的判断
//在累加时,我们加上了n/2个a[i] - b[i],对于这些,我们选的都是a[i],所以加上b[i}后价格就对了
//对于剩下的n/2个我们选的就是b[i].
//所以,在加完n/2个a[i]-b[i]后,最终再加上n个b就是最佳选法 。
ll sb = 0;
//注意这里是-N 到 N,所以区间还要开大点
struct Node
{
int l,r,siz;
ll sum[4];
}tr[N << 3];
void pushup(int u)
{
tr[u].siz = tr[u<<1].siz + tr[u<<1|1].siz;
for(int i = 0;i<4;i++)
{
//注意这里不是+=而是=
//左区间的前k个就是总区间的前k个,所以一模一样
tr[u].sum[i] = tr[u<<1].sum[i];
}
int lz = tr[u<<1].siz;
for(int i = 0;i<4;i++)
{
//注意以下是+=不是=
//这里右侧区间是在总区间的sum根据左侧区间重置之后的累加
//原本总区间的sum就是左右区间的累加,这里先有了左区间罢了
//如果互换顺序,同样是先=后+=
tr[u].sum[(lz + i) % 4] += tr[u<<1|1].sum[i];
}
}
void build(int u,int l,int r)
{
tr[u] = {l,r,0};
if(l == r)
{
return;
}
int mid = l + r >> 1;
build(u << 1,l,mid);
build(u<<1|1,mid + 1,r);
}
void update(int u,ll v,int k)
{
if(tr[u].l == tr[u].r)
{
// % 4 有偏移量
// 1 : 0
// 2 : 1
// 3 : 2
// 4 : 3
// 5 : 4
if(k == 1)
{
// 到这里我们l == r,区间中只有一个数字
// 如果这个数字存在,那么他在区间中的位置应该是 %4 ==0
// 也就是第一个被选的位置
// 这里siz初始为0,后面才加上,所以不用一个偏移量直接加上
tr[u].sum[tr[u].siz % 4] += v;
}
else
{
// 如果已经存在,现在我们要剪掉,那么也应当是第一个位置 %4 = 0
// 这里的区间大小就有一个偏移量,要减去
tr[u].sum[(tr[u].siz - 1) % 4] -= v;
}
// 错解: tr[p].sum[0] += loc * k; 相同的数也应当要排名
// 上面 N B,相同的数在选的时候也有偏移量
tr[u].siz += k;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if(v <= mid)
{
update(u<<1,v,k);
}
else
{
update(u<<1|1,v,k);
}
pushup(u);
}
ll query()
{
int u = 1;
ll res = 0;
ll sl = 0;
ll sr = 0;
// 对正负数分别查询即可
sl += tr[u<<1].sum[0] + tr[u<<1].sum[3];
// 左侧是 <= 0的正收益
// 假设有x个物品正收益的
// x = 2 : tr[ls].siz = 4; ABBA,负收益部分是A开始 : ABABA 右半部分我们取 % 4 == 0 || 2
// x = 3 : tr[ls].siz = 6; ABBAAB ,负收益部分是B开始 : BABABA 右半部分我们取 % 4 == 1 || 3
// x = 4 : tr[ls].siz = 8;
if(tr[u<<1].siz * 2 % 4)
{
sr += tr[u<<1|1].sum[1] + tr[u<<1|1].sum[3];// 判断是谁取完的情况1 ,那么就是谁开始取情况2
}
else
{
sr += tr[u<<1|1].sum[0] + tr[u<<1|1].sum[2];
}
res = sl + sr + sb;
return res;
}
void solve()
{
build(1,-N,N);
cin>>n>>m;
vector<ll> a(n + 1),b(n + 1);
for(int i = 1;i<=n;i++)
{
scanf("%lld %lld",&a[i],&b[i]);
sb += b[i];
update(1,a[i] - b[i],1);
}
cout<<query()<<endl;
for(int i = 1;i<=m;i++)
{
//下标都是t
int t,ac,bc;
cin>>t>>ac>>bc;
update(1,a[t] - b[t],-1);
update(1,ac - bc ,1);
//这里别减错了
sb -= b[t] - bc;
a[t] = ac;
b[t] = bc;
cout<<query()<<endl;
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cin.sync();
int t = 1;
while(t--)
{
solve();
}
return 0;
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 0
Dangerous Syscalls
input:
4 5 2 4 5 7 1 7 2 1 4 5 2 1 6 2 4 4 3 2 1 3 3 6 6
output:
0 4 6 5 -4104 -4100