zoukankan      html  css  js  c++  java
  • [bzoj3747][POI2015]Kinoman_线段树

    Kinoman bzoj-3747 POI-2015

    题目大意:有m部电影,第i部电影的好看值为w[i]。现在放了n天电影,请你选择一段区间l~r使得l到r之间的好看值总和最大。特别地,如果同一种电影放了两遍及以上,那么这种电影的好看值将不会被获得。

    注释:$1le m le n le 10^6$。

    想法:和rmq problem类似的,我们处理出每一个位置pos右边第一个和pos上电影种类相同的位置nxt[pos]。然后,我从1-n扫一遍,每次讲l+1到nxt[l]-1之间的值加上w[a[l]],这个过程可以用线段树维护。

    最后,附上丑陋的代码... ...

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 1000050
    #define lson pos<<1
    #define rson pos<<1|1
    typedef long long ll;
    ll t[N<<2],lazy[N<<2];
    int f[N],w[N],nxt[N],n,m,now[N];
    char nc()
    {
        static char buf[100000],*p1,*p2;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int rd()
    {
        register int x=0;
        register char s=nc();
        while(s<'0'||s>'9')s=nc();
        while(s>='0'&&s<='9')x=(x<<3)+(x<<1)+s-'0',s=nc();
        return x;
    }
    void pushdown(int pos)
    {
    	if(!lazy[pos]) return;
    	ll d=lazy[pos];
    	lazy[lson]+=d; lazy[rson]+=d;
    	t[lson]+=d; t[rson]+=d;
    	lazy[pos]=0;
    }
    void update(int l,int r,int x,int y,ll v,int pos)
    {
    	if(x<=l&&y>=r)
    	{
    		t[pos]+=v; lazy[pos]+=v;
    		return;
    	}
    	pushdown(pos);
    	int mid=(l+r)>>1;
    	if(x<=mid) update(l,mid,x,y,v,lson);
    	if(y>mid) update(mid+1,r,x,y,v,rson);
    	t[pos]=max(t[lson],t[rson]);
    }
    int main()
    {
    	n=rd(),m=rd();
    	for(int i=1;i<=n;i++)
    	{
    		f[i]=rd();
    	}
    	for(int i=1;i<=m;i++)
    	{
    		w[i]=rd();
    	}
    	for(int i=n;i;i--)
    	{
    		nxt[i]=now[f[i]];
    		now[f[i]]=i;
    	}
    	for(int i=1;i<=m;i++)
    	{
    		if(now[i])
    		{
    			if(!nxt[now[i]]) update(1,n,now[i],n,w[i],1);
    			else update(1,n,now[i],nxt[now[i]]-1,w[i],1);
    		}
    	}
    	ll ans=0;
    	for(int i=1;i<=n;i++)
    	{
    		ans=max(ans,t[1]);
    		if(nxt[i])
    		{
    			update(1,n,i,nxt[i]-1,-w[f[i]],1);
    			if(nxt[nxt[i]]) update(1,n,nxt[i],nxt[nxt[i]]-1,w[f[i]],1);
    			else update(1,n,nxt[i],n,w[f[i]],1);
    		}
    		else update(1,n,i,n,-w[f[i]],1);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }

    小结:线段树能干好多事情啊qwq

  • 相关阅读:
    归并排序(Merge Sort)
    AtCoder AGC035D Add and Remove (状压DP)
    AtCoder AGC034D Manhattan Max Matching (费用流)
    AtCoder AGC033F Adding Edges (图论)
    AtCoder AGC031F Walk on Graph (图论、数论)
    AtCoder AGC031E Snuke the Phantom Thief (费用流)
    AtCoder AGC029F Construction of a Tree (二分图匹配)
    AtCoder AGC029E Wandering TKHS
    AtCoder AGC039F Min Product Sum (容斥原理、组合计数、DP)
    AtCoder AGC035E Develop (DP、图论、计数)
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9085045.html
Copyright © 2011-2022 走看看