loj2275 「JXOI2017」颜色

枚举右端点,然后看左端点合法情况。

先预处理每个颜色 \(i\) 的最大出现位置 \(max_i\) 和最小出现位置 \(min_i\)。对于枚举右端点在一个位置 \(i\),凡是 \(max_k > i\) 的颜色 \(k\) 都是不能要的。那么要满足右端点往右都合法,就要找出一个 \(j < i\)\(max_{col_j} > i\) 这样的最大的 \(j\)。那么左端点就可以在 \((j,i]\) 之间了。

再来满足左端点往左都合法。对于一个颜色 \(k\),当 \(max_k \leq i\) 时,左端点显然不能在 \((min_k,max_k]\) 之间。线段树+栈解决问题。

参考

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
int T, n, col[300005], minn[300005], maxn[300005], sta[300005], din;
const int oo=0x3f3f3f3f;
ll ans;
struct SGT{
	int sum[1200005];
	bool tag[1200005];
	void build(int o, int l, int r){
		sum[o] = tag[o] = 0;
		if(l==r)	;
		else{
			int mid=(l+r)>>1;
			int lson=o<<1;
			int rson=lson|1;
			if(l<=mid)	build(lson, l, mid);
			if(mid<r)	build(rson, mid+1, r);
		}
	}
	void pushDown(int o, int l, int r, int lson, int rson, int mid){
		sum[lson] = mid - l + 1;
		sum[rson] = r - mid;
		tag[lson] = true;
		tag[rson] = true;
		tag[o] = false;
	}
	void update(int o, int l, int r, int x, int y){
		if(l>r)	return ;
		if(l>=x && r<=y){
			sum[o] = (r - l + 1);
			tag[o] = true;
		}
		else{
			int mid=(l+r)>>1;
			int lson=o<<1;
			int rson=lson|1;
			if(tag[o])	pushDown(o, l, r, lson, rson, mid);
			if(x<=mid)	update(lson, l, mid, x, y);
			if(mid<y)	update(rson, mid+1, r, x, y);
			sum[o] = sum[lson] + sum[rson];
		}
	}
	int query(int o, int l, int r, int x, int y){
		if(l>r)	return 0;
		if(l>=x && r<=y)	return sum[o];
		else{
			int mid=(l+r)>>1;
			int lson=o<<1;
			int rson=lson|1;
			int re=0;
			if(tag[o])	pushDown(o, l, r, lson, rson, mid);
			if(x<=mid)	re += query(lson, l, mid, x, y);
			if(mid<y)	re += query(rson, mid+1, r, x, y);
			return re;
		}
	}
}sgt;
int main(){
	cin>>T;
	while(T--){
		scanf("%d", &n);
		ans = din = 0;
		for(int i=1; i<=n; i++){
			scanf("%d", &col[i]);
			minn[col[i]] = oo;
			maxn[col[i]] = 0;
		}
		for(int i=1; i<=n; i++){
			minn[col[i]] = min(minn[col[i]], i);
			maxn[col[i]] = max(maxn[col[i]], i);
		}
		sgt.build(1, 1, n);
		for(int i=1; i<=n; i++){
			if(i==maxn[col[i]])
				sgt.update(1, 1, n, minn[col[i]]+1, i);
			sta[++din] = i;
			while(din && maxn[col[sta[din]]]<=i)	din--;
			int pos=!din?1:sta[din]+1;
			ans += (i - pos + 1) - sgt.query(1, 1, n, pos, i);
		}
		printf("%lld\n", ans);
	}
	return 0;
}
posted @ 2018-04-16 14:48  poorpool  阅读(386)  评论(0编辑  收藏  举报