zoukankan      html  css  js  c++  java
  • JXOI2017颜色

    题面

    loj

    分析

    这道题非常妙啊
    对于可保留区间[l, r]
    枚举右端点r
    考虑l的取值范围有两重约数
    记颜色i出现的最右侧位置是(max_i) 最左侧位置是(min_i)
    r前最后一次出现的位置是pre[i]
    1.若max[i] > r 则 l > pre[i]
    2.若max[i] <= r 则 l 不能取(min[i], max[i] ]
    限制一维护一下单调栈就好啦 限制二线段树维护一下

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    using namespace std;
    const int N = 3e5 + 5;
    const int inf = 0x3f3f3f3f;
    int n, a[N], mx[N], mn[N];
    long long ans;
    int stk[N], top;
    
    struct Seg{
    	int w[N << 2]; bool flag[N << 2];
    	void update(int rt){
    		w[rt] = w[rt << 1] + w[rt << 1 | 1];
    	}
    	void pushdown(int rt, int l, int r){
    		if(!flag[rt]) return ;
    		int mid = l + ((r - l) >> 1);
    		w[rt << 1] = mid - l + 1;
    		w[rt << 1 | 1] = r - mid;
    		flag[rt << 1] = flag[rt << 1 | 1] = 1;
    		flag[rt] = 0;
    	}
    	void clr(int rt, int l, int r){
    		w[rt] = flag[rt] = 0;
    		if(l == r) return ;
    		int mid = l + ((r - l) >> 1);
    		clr(rt << 1, l, mid);
    		clr(rt << 1 | 1, mid + 1, r);
    	}
    	void mdf(int rt, int l, int r, int x, int y){
    		if(l > r) return ;
    		if(l >= x && r <= y){
    			w[rt] = r - l + 1; flag[rt] = 1;
    			return ;
    		}
    		pushdown(rt, l, r);
    		int mid = l + ((r - l) >> 1);
    		if(x <= mid) mdf(rt << 1, l, mid, x, y);
    		if(y > mid) mdf(rt << 1 | 1, mid + 1, r, x, y);
    	    update(rt);
    	}
    	int qry(int rt, int l, int r, int x, int y){
    		if(l > r) return 0;
    		if(l >= x && r <= y) return w[rt];
    		pushdown(rt, l, r);
    		int mid = l + ((r - l) >> 1), ret = 0;
    		if(x <= mid) ret += qry(rt << 1, l, mid, x, y);
    		if(y > mid) ret += qry(rt << 1 | 1, mid + 1, r, x, y);
    	    return ret;
    	}
    }seg; 
    
    int main(){
    	int T; scanf("%d", &T);
    	while(T--){
    		scanf("%d", &n);
    		
    		seg.clr(1, 1, n);
    		for(int i = 0; i <= n; ++i) mx[i] = 0, mn[i] = inf;
    		
    		for(int i = 1; i <= n; ++i){
    			scanf("%d", &a[i]);
    		    mx[a[i]] = max(mx[a[i]], i);
    		    mn[a[i]] = min(mn[a[i]], i);
    		}
    		ans = 0;
    		top = 0;
    		mn[0] = mx[0] = 0;
     		for(int r = 1; r <= n; ++r){
    			if(r == mx[a[r]] && r > mn[a[r]]){
    				seg.mdf(1, 1, n, mn[a[r]] + 1, r);
    			//	printf("%d %d
    ", mn[a[r]] + 1, r);
    			}
    			stk[++top] = r;
    			while(top && mx[a[stk[top]]] <= r) --top;
    			//这里维护颜色调了好久 蠢了蠢了 注意那个pre不是单调递增的哦 
    			
    			ans += (r - stk[top] - seg.qry(1, 1, n, stk[top] + 1, r));
    			//printf("ans = %d %d %d %d %d %d
    ", ans, r, stk[top], stk[top] + 1, r, seg.qry(1, 1, n, stk[top] + 1, r));
    		}
    		printf("%lld
    ", ans);
    	}
    	return 0;	
    }
    
  • 相关阅读:
    time 模块学习
    day 14 自定义模块,常用模块 time .datetime ,time 模块
    day 13 课后作业
    day 12 课后作业
    day 11课后作业
    树状数组最值
    hdu 1059 Dividing bitset 多重背包
    XVII Open Cup named after E.V. Pankratiev. XXI Ural Championship
    最长公共子序列板/滚动 N^2
    Uva 10635
  • 原文地址:https://www.cnblogs.com/hjmmm/p/10624563.html
Copyright © 2011-2022 走看看