[树状数组]洛谷 P3586 LOG 题解

这个结论的说明其实洛谷的第一篇题解写的很清楚了 qwq

相当于是根据离散值建权值树状数组,动态维护大于 s 的种类的数量,和小于 s 的种类的和,然后在维护一下这个数组本身的值就行了。

注意哦,这里离散是要把查询更新一起离线离散的

具体实现还是有点麻烦的,好像别的题解都没仔细写,那么我来详细展开一下罢

#include <bits/stdc++.h>

#define int long long
#define qwq return 0
#define ri register int
#define N 1000007
#define lowbit(x) (x & -x)

int len , n , m  , a[N] , b[N] , d[N] , tree1[N] , tree2[N];

struct option {
	char type;
	int c/*k*/ , s/*a*/;
}opt[N << 1];

using namespace std;

inline void update(int *s , int x , int k) {
	if(!x) {
		return;
	}
	while(x <= len) {
		s[x] += k;
		x += lowbit(x);
	}
}

inline int sum(int *s , int x) {
	int r = 0;
	while(x) {
		r += s[x];
		x -= lowbit(x);
	}
	return r;
}

signed main()
{
	cin >> n >> m;
	for(ri i = 1; i <= m; ++i) {
		cin >> opt[i].type >> opt[i].c >> opt[i].s;
		b[i] = a[i] = opt[i].s;
	}	
	sort(a + 1 , a + m + 1);
	len = unique(a + 1 , a + m + 1) - a - 1;
	for(ri i = 1; i <= m ; ++i) {
		b[i] = lower_bound(a + 1 , a + len + 1 , b[i]) - a;	//离散化后,每个命令的离散值
	}
	for(ri i = 1; i <= m; ++i) {
		switch(opt[i].type) {
			case 'U' : {
				update(tree1 , d[opt[i].c] , - 1);//由于是修改,要先把原来的值给去了
				update(tree1 , b[i] , 1); //再加上新值
				update(tree2 , d[opt[i].c] , -a[d[opt[i].c]]); //这里更改时要用离散前的值
				update(tree2 , b[i] , a[b[i]]);
				d[opt[i].c] = b[i];//d相当于是我们动态维护的这个数组本身
				break;
			}
			case 'Z' : {
				int y = sum(tree1 , len) - sum(tree1 , b[i] - 1);//大于s数量
				int x = sum(tree2 , b[i] - 1) + y * opt[i].s;//小于s的和
				//把大于s的全剪成s,其他的加上即可
				cout << ((x >= opt[i].c * opt[i].s) ? "TAK" : "NIE") <<'\n';
				break;
			} 
		}
	}
	
	qwq;
}
posted @ 2025-03-13 19:10  「癔症」  阅读(14)  评论(0)    收藏  举报