QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#154528#5441. Quartz Collectionvalue0RE 0ms0kbC++203.6kb2023-08-31 18:47:442023-08-31 18:47:45

Judging History

你现在查看的是最新测评结果

  • [2023-08-31 18:47:45]
  • 评测
  • 测评结果:RE
  • 用时:0ms
  • 内存:0kb
  • [2023-08-31 18:47:44]
  • 提交

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;
}

詳細信息

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

result: