zoukankan      html  css  js  c++  java
  • 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
    ", ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Oracle创建用户并赋予权限
    Oracle查询表空间使用情况
    Oracle更改数据库文件大小、实时增加文件容量
    Oracle查询数据中占用空间最大的表
    Oracle存储包存储及案例
    Oracle包Package调用Package
    Oracle存储过程Procedure语法及案例
    Oracle存储过程function语法及案例
    Oracle常用语法
    Oracle游标循环更新数据案例
  • 原文地址:https://www.cnblogs.com/poorpool/p/8855846.html
Copyright © 2011-2022 走看看