• BZOJ 3747: [POI2015]Kinoman(线段树)


    传送门

    解题思路

      遇到这种选区间的题,很多时候都是枚举左端点,然后计算右端点。考虑枚举左端点之后如何维护,设下一部和(i)这个位置的电影相同的为(nxt[i]),那么如果左端点从(i)移动到(i+1)([i+1,nxt[i]-1])这段区间会减少(w[f[i]]),而([nxt[i],nxt[nxt[i]]-1)会增加(w[f[i]]),发现可以线段树维护。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    
    using namespace std;
    const int N=1000005;
    typedef long long LL;
    
    inline int rd(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
    	while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return f?x:-x;	
    }
    
    inline LL max(LL x,LL y){return x>y?x:y;}
    
    int n,m,pre[N],w[N],nxt[N],cnt[N],f[N];
    LL ans,Max[N<<2],tag[N<<2];
    
    inline void pushdown(int x){
    	Max[x<<1]+=tag[x];Max[x<<1|1]+=tag[x];
    	tag[x<<1]+=tag[x];tag[x<<1|1]+=tag[x];
    	tag[x]=0;	
    }
    
    void update(int x,int l,int r,int L,int R,LL k){
    	if(L>R) return ;
    	if(L<=l && r<=R) {Max[x]+=k;tag[x]+=k;return ;} 
    	int mid=(l+r)>>1;if(tag[x]) pushdown(x);
    	if(L<=mid) update(x<<1,l,mid,L,R,k);
    	if(mid<R) update(x<<1|1,mid+1,r,L,R,k);
    	Max[x]=max(Max[x<<1],Max[x<<1|1]);
    }	
    
    LL query(int x,int l,int r,int L,int R){
    	if(L<=l && r<=R) return Max[x];
    	int mid=(l+r)>>1;if(tag[x]) pushdown(x); 	
    	if(L>mid) return query(x<<1|1,mid+1,r,L,R);
    	else if(R<=mid) return query(x<<1,l,mid,L,R);
    	else return max(query(x<<1,l,mid,L,R),query(x<<1|1,mid+1,r,L,R));
    }
    
    signed main(){
    	n=rd(),m=rd();int x;
    	for(int i=1;i<=n;i++){
    		x=rd();f[i]=x;
    		if(pre[x]) nxt[pre[x]]=i;
    		pre[x]=i;	
    	}
    	LL now=0;
    	for(int i=1;i<=m;i++) w[i]=rd();
    	for(int i=1;i<=n;i++){
    		if(!cnt[f[i]]) now+=w[f[i]];
    		else if(cnt[f[i]]==1) now-=w[f[i]];
    		cnt[f[i]]++;update(1,1,n,i,i,now);
    	}
    	for(int i=1;i<=n;i++){
    		ans=max(ans,query(1,1,n,i,n));
    		if(!nxt[i]) update(1,1,n,i+1,n,-w[f[i]]);
    		else update(1,1,n,i+1,nxt[i]-1,-w[f[i]]);
    		if(nxt[i] && !nxt[nxt[i]]) update(1,1,n,nxt[i],n,w[f[i]]);
    		else update(1,1,n,nxt[i],nxt[nxt[i]]-1,w[f[i]]);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }	
    
  • 相关阅读:
    ✡ leetcode 169. Majority Element 求出现次数最多的数 --------- java
    ✡ leetcode 168. Excel Sheet Column Title 26进制数字 --------- java
    ✡ leetcode 167. Two Sum II
    ✡ leetcode 166. Fraction to Recurring Decimal 分数转换 --------- java
    javascript XMLHttpRequest对象全面剖析
    百度Echarts使用心得
    纯CSS画的基本图形(矩形、圆形、三角形、多边形、爱心、八卦等)
    css阴影--box-shadow的用法
    background小结
    20150103笔记
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10261901.html
Copyright © 2020-2023  润新知