zoukankan      html  css  js  c++  java
  • 2019杭电多校二 L. Longest Subarray (线段树)

    大意: 给定序列$a$, 元素范围$[1,C]$, 求一个最长子序列, 满足每个元素要么不出现, 要么出现次数$le K$.

    枚举右端点, 考虑左端点合法的位置. 显然一定是$C$种颜色合法位置的交, 可以用线段树维护合法颜色的种类数, 每次二分出最小的满足合法个数为$C$的位置更新答案.

    考虑右端点移动到$i$, 位置$i$的颜色为$x$, 存在一个位置$p_{x}$, 满足

    对于颜色$x$的合法区间为$[1,p_{x}]$, 不合法区间为$[p_{x}+1,i]$.

    在右端点的移动过程中, 维护上次计算的增量即可.

    也就是说每次对$[p'_{x}+1,p_{x}]$区间加, $[{pre}_x+1,i]$区间减.

    $p'_{x}$为上次计算时的分界点, ${pre}_x$为$x$上次出现位置

    类似题目可以做一下[POI2015]KIN, 也是对每种颜色维护一个增量.

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define hr puts("")
    using namespace std;
    const int N = 1e6+10;
    int n, c, k, a[N];
    vector<int> v[N];
    struct _ {
    	int ma,tag,pos;
    	void upd(int x) {ma+=x,tag+=x;}
    	_ operator + (const _ &rhs) const {
    		_ ret;
    		ret.ma = max(ma, rhs.ma);
    		ret.pos = ret.ma==ma?pos:rhs.pos;
    		ret.tag = 0;
    		return ret;
    	}
    } tr[N<<2];
    void build(int o, int l, int r) {
    	tr[o].ma=c,tr[o].tag=0,tr[o].pos=l;
    	if (l!=r) build(ls),build(rs);
    }
    void pd(int o) {
    	if (tr[o].tag) {
    		tr[lc].upd(tr[o].tag);
    		tr[rc].upd(tr[o].tag);
    		tr[o].tag=0;
    	}
    }
    void add(int o, int l, int r, int ql, int qr, int v) {
    	if (l>qr||r<ql) return;
    	if (ql<=l&&r<=qr) return tr[o].upd(v);
    	pd(o),add(ls,ql,qr,v),add(rs,ql,qr,v),tr[o]=tr[lc]+tr[rc];
    }
    int qry(int o, int l, int r, int ql, int qr) {
    	if (l>qr||r<ql||tr[o].ma!=c) return 0;
    	if (ql<=l&&r<=qr) return tr[o].pos;
    	pd(o);
    	int t = qry(ls,ql,qr);
    	return t?t:qry(rs,ql,qr);
    }
    int main() {
    	while (~scanf("%d%d%d",&n,&c,&k)) {
    		REP(i,1,n) scanf("%d",a+i);
    		REP(i,1,c) v[i].clear(),v[i].pb(0);
    		int ans = 0;
    		build(1,1,n);
    		REP(i,1,n) {
    			if (v[a[i]].back()+1<=i) add(1,1,n,v[a[i]].back()+1,i,-1);
    			v[a[i]].pb(i);
    			int p = v[a[i]].size()-k-1;
    			if (p>=0) add(1,1,n,v[a[i]][p]+1,v[a[i]][p+1],1);
    			int j = qry(1,1,n,1,i);
    			if (j) ans = max(ans, i-j+1);
    		}
    		printf("%d
    ",ans);
    	}
    }
    
  • 相关阅读:
    python 合并 Excel 单元格
    python 设置 Excel 表格的行高和列宽
    Python 用 openpyxl 模块统计 Excel 表格中的数据,以字典形式写入 py 文件
    python 打印字母阶梯和金字塔
    python 用 openpyxl 读取 Excel 表格中指定的行或列
    Python 的 filter() 函数
    Python 的 map() 函数
    python 之 range() 函数
    python 的 reduce() 函数
    python 之 lambda 函数
  • 原文地址:https://www.cnblogs.com/uid001/p/11242982.html
Copyright © 2011-2022 走看看