icpc 2020 澳门 J Jewel Grab (线段树+set)

题目链接:https://codeforces.com/gym/103119/problem/J

看到 (k) 只有 (10),所以可以暴力跳段统计答案

维护每个位置前一个相同颜色出现的位置 (pre[i]),如果 (pre[i] < s),则说明该颜色没有在 (s) 之后出现过,在线段树上二分找到第一个 (pre[x] > s)(x) 即可

(pre) 的修改要用 (set) 维护一下每个颜色都在哪些位置出现过,修改的时候细心一些,注意不要漏掉 (set, la(某个颜色最后出现的位置))

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 200010;
const int INF = 1000000007;

int n, m;
ll v[maxn], mvc[maxn]; 
int c[maxn], pre[maxn], nxt[maxn], la[maxn];

set<int> cp[maxn];

struct Node{
	int mx;
	ll sum;
}t[maxn<<2];

void pushup(int i){
	t[i].mx = max(t[i<<1].mx, t[i<<1|1].mx); 
	t[i].sum = t[i<<1].sum + t[i<<1|1].sum;
}

void build(int i, int l, int r){
	if(l == r){
		t[i].mx = pre[l];
		t[i].sum = v[l];
		return;
	}
	
	int mid = (l + r) >> 1;
	build(i << 1, l, mid); build(i << 1 | 1, mid + 1, r);
	pushup(i); 
}

void modify(int i, int p, int l, int r){
	if(l == r){
		t[i].mx = pre[l];
		t[i].sum = v[l];
		return;
	}
	
	int mid = (l + r) >> 1;
	if(p <= mid) modify(i<<1, p, l, mid);
	else modify(i<<1|1, p, mid + 1, r);
	pushup(i);
}

ll query(int i, int l, int r, int x, int y){
	if(x <= l && r <= y){
		return t[i].sum;
	}
	int mid = (l + r) >> 1;
	ll res = 0;
	if(x <= mid) res += query(i<<1, l, mid, x, y);
	if(y > mid) res += query(i<<1|1, mid + 1, r, x, y);
	return res;
}

int find(int i, int s, int l, int r, int p){ 
	if(l == r){
		return l;
	}
	
	int mid = (l + r) >> 1;
	
	int pos = -1;
	if(t[i<<1].mx >= s && p <= mid) pos = find(i<<1, s, l, mid, p); 
	if(pos != -1) return pos;
	if(t[i<<1|1].mx >= s) pos = find(i<<1|1, s, mid+1, r, p);
	return pos;
}

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	n = read(), m = read();
	
	memset(la, -1, sizeof(la));
	for(int i = 1 ; i <= n ; ++i){
		c[i] = read(), v[i] = read(); 
		cp[c[i]].insert(i);
		pre[i] = la[c[i]];
		la[c[i]] = i;	
	} 
	
	memset(la, -1, sizeof(la));
	for(int i = n ; i >= 1 ; --i){
		nxt[i] = la[c[i]];
		la[c[i]] = i; 
	}

	memset(la, -1, sizeof(la));
	for(int i = 1 ; i <= n ; ++i) la[c[i]] = i;
	
	build(1, 1, n);

	int op, k, x, y;
	for(int i = 1 ; i <= m ; ++i){
		op = read();
		if(op == 1) {
			x = read(), y = read(), k = read();
			cp[c[x]].erase(x);
			if(la[c[x]] == x) la[c[x]] = pre[x];
			v[x] = k;
			c[x] = y;
			
			if(nxt[x] != -1){
				if(pre[x] != -1){
					nxt[pre[x]] = nxt[x];
					pre[nxt[x]] = pre[x];
					modify(1, nxt[x], 1, n);
				} else{
					pre[nxt[x]] = -1;
					modify(1, nxt[x], 1, n);
				}
			} else {
				if(pre[x] != -1){
					nxt[pre[x]] = -1;
				} 
			}
			
			int pos;
			set<int>::iterator it;
			it = cp[y].lower_bound(x);
			if(it == cp[y].end()) {
				nxt[x] = -1;
				pre[x] = la[y];
				if(pre[x] != -1) nxt[pre[x]] = x;
				modify(1, x, 1, n);
			}
			else {
				pos = *it;
				if(pre[pos] != -1){
					nxt[pre[pos]] = x;
					pre[x] = pre[pos];
					modify(1, x, 1, n);				
				} else{
					pre[x] = -1;
					modify(1, x, 1, n);
				}				
				
				nxt[x] = pos;
				pre[pos] = x;
				modify(1, pos, 1, n);	
			}
			
			cp[y].insert(x);
			la[y] = max(la[y], x);
		} else{
			vector<int> color;
			color = vector<int>();
			x = read(), k = read();
			int cur = x;
			
			ll ans = 0;
			for(int j = 0 ; j <= k && cur <= n ; ++j){
				int pos = find(1, x, 1, n, cur);
				if(pos == -1){
					ans += query(1, 1, n, cur, n);
					break;
				}
				
				color.push_back(c[pos]);
				if(j < k) {
					if(mvc[c[pos]] == 0) mvc[c[pos]] = v[pre[pos]];
					if(v[pos] > mvc[c[pos]]){
						ans -= mvc[c[pos]];
						ans += v[pos];
						mvc[c[pos]] = v[pos];
					}	
				}
				
				ans += query(1, 1, n, cur, pos-1);
				cur = pos + 1;
			}
			printf("%lld
", ans);
			
			for(auto u : color) mvc[u] = 0;
		}
	}
	
	return 0;
}
原文地址:https://www.cnblogs.com/tuchen/p/15189004.html