zoukankan      html  css  js  c++  java
  • BZOJ 3747: [POI2015]Kinoman

    经典颜色问题推荐博文

    https://www.cnblogs.com/tyner/p/11519506.html

    https://www.cnblogs.com/tyner/p/11616770.html

    https://www.cnblogs.com/tyner/p/11620894.html

    题意:

    https://www.lydsy.com/JudgeOnline/problem.php?id=3747
    m 个不同颜色的点,每个点有个权值,现在由这 m 种颜色的点组成的长度为 n 的序列
    求一个区间,这个区间内只出现一次的点的权值和最大

    参考博客:http://hzwer.com/5715.html

    分析

    这种和颜色出现次数相关的题比较正常的想法就是枚举左端点,并计算出nxt[i] (与坐标 i 的颜色相同的下一个位置坐标

    右移左端点的时候,处理“右移”这个操作对[l, nxt[l]-1] 以及 [nxt[l] , n] 这两个区间中答案的的影响。

    注意可能有颜色不在序列中的情况

    这题数据要开longlong

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long
    const int MAX = 1000000+99;
    
    int n,m;
    ll ans; 
    int nxt[MAX], lst[MAX];
    int f[MAX], w[MAX];
    struct tree{
    	ll add, mx;
    }tr[MAX<<2];
    
    void pushup(int o) {tr[o].mx = max(tr[o<<1].mx, tr[o<<1|1].mx);}
    //void build(){}
    void pushdown(int o) {
    	if(0 == tr[o].add) return ;
    	tr[o<<1].add += tr[o].add;
    	tr[o<<1|1].add += tr[o].add;
    	tr[o<<1].mx += tr[o].add;
    	tr[o<<1|1].mx += tr[o].add;
    	tr[o].add = 0;
    }
    void optadd(int o, int l, int r, int ql, int qr, int k) {
    	if(ql<=l && r<=qr) {
    		tr[o].add += k;
    		tr[o].mx += k;
    		return ;
    	}
    	int mid = (l+r)>>1;
    	pushdown(o);
    	if(ql <= mid) optadd(o<<1, l, mid, ql, qr, k);
    	if(mid < qr) optadd(o<<1|1, mid+1, r, ql, qr, k);
    	pushup(o);
    }
    
    int main() {
    	scanf("%d%d",&n,&m);
    	for(int i = 1; i <= n; i++) scanf("%d",&f[i]);
    	for(int j = 1; j <= m; j++) scanf("%d",&w[j]);
    	for(int i = n; i >= 1; i--) {
    		nxt[i] = lst[f[i]];
    		lst[f[i]] = i;
    	}
    	for(int i = 1; i <= m; i++) //先初始化左端点为 1 的情况(即处理每种颜色的第一个位置对答案的影响)
    		if(lst[i]) {//注意判是否在序列中存在这个颜色(万一没有呢) 
    			if(!nxt[lst[i]]) optadd(1, 1, n, lst[i], n, w[i]);//别越界了,时刻注意nxt,lst的含义 
    			else optadd(1, 1, n, lst[i], nxt[lst[i]]-1, w[i]); 
    		}
    	int t;
    	for(int i = 1; i <= n; i++) {
    		ans = max(ans, tr[1].mx);//当左端点为 i 时,去的最大答案
    		t = nxt[i];//以下表示左端点移到 i+1 后对答案的影响 
    		if(t) {
    			optadd(1, 1, n, i, t-1, -w[f[i]]);
    			if(nxt[t]) optadd(1, 1, n, t, nxt[t]-1, w[f[i]]);
    			else optadd(1, 1, n, t, n, w[f[i]]);
    		} else optadd(1, 1, n, i, n, -w[f[i]]);
    	}
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    Dos常用命令收集
    build.xml
    ActionScript. 3.0著名开源库 大集合
    知识:ASP.NET ViewState
    分享:JavaScript表格排序控制
    分享:ViewState压缩方法
    分享:获取Castle.ActiveRecord中的Nhibernate Session
    分享:ASP.NET避免VIEWSTATE过大
    分享:扩展Include关联查询
    积累:收集常用sql
  • 原文地址:https://www.cnblogs.com/tyner/p/11519506.html
Copyright © 2011-2022 走看看