• P2605 [ZJOI2010]基站选址 线段树优化DP


    题意:

    戳这里查看

    分析:

    我们发现题目里面每一个建立的基站可能会对之前的状态有所影响,所以我们在设计DP状态时需要将这种影响消除掉

    我们设(f[i][j])表示在第(i)个村庄修建第(j)个基站且不考虑对([i+1,n])个村庄的影响时的最小费用

    • 转移方程就是 (f[i][j]=min(f[k][j-1]+cost[k][i]+c[i])),其中(cost[k][i])表示在(i,k)建立基站后,([k+1,i-1])内没有被覆盖的村庄赔付的和值,这样的DP复杂度是(O(n^2k))
    • 我们考虑怎么优化,首先可以滚动数组滚掉一维,(f[i]=min(f[k]+cost[k][i])+c[i])
    • 然后我们发现对于(cost[k][i])来说,每个村庄的贡献时独立的,我们记(lef[i],rig[i])表示每一个村庄能接受信号的左右边界,那么对于第(i)个村庄安装基站时,从([1,lef[k]-1])转移来的状态必定会赔付村庄(k)的费用
    • 也就是说我们我们需要一个支持区间修改,区间查询最小值的数据结构,所以我们用线段树维护(f[k]+cost[k][i])(此时(i)是在外层枚举的,线段树只要维护(k)的信息就可以了),复杂度(O(nlog_nk))

    代码:

    #include<bits/stdc++.h> 
    using namespace std;
    
    namespace zzc
    {
    	const int maxn = 2e4+5;
    	const int inf = 0x3f3f3f3f;
    	int n,k,ans;
    	int c[maxn],w[maxn],s[maxn],f[maxn],d[maxn],lef[maxn],rig[maxn],val[maxn<<3],tag[maxn<<3];
    	vector<int> pos[maxn];
    	
    	void pushup(int x)
    	{
    		val[x]=min(val[x<<1],val[x<<1|1]);
    	}
    	
    	void pushdown(int x)
    	{
    		if(!tag[x]) return ;
    		tag[x<<1]+=tag[x];
    		tag[x<<1|1]+=tag[x];
    		val[x<<1]+=tag[x];
    		val[x<<1|1]+=tag[x];
    		tag[x]=0;
    	}
    	
    	void build(int rt,int l,int r)
    	{
    		tag[rt]=0;
    		if(l==r)
    		{
    			val[rt]=f[l];
    			return ;
    		}
    		int mid=(l+r)>>1;
    		build(rt<<1,l,mid);
    		build(rt<<1|1,mid+1,r);
    		pushup(rt);
    	}
    	
    	void update(int rt,int l,int r,int ll,int rr,int v)
    	{
    		if(l>r) return ;
    		if(l>=ll&&r<=rr) 
    		{
    			val[rt]+=v;
    			tag[rt]+=v;
    			return ;
    		}
    		pushdown(rt);
    		int mid=(l+r)>>1;
    		if(ll<=mid) update(rt<<1,l,mid,ll,rr,v);
    		if(mid<rr) update(rt<<1|1,mid+1,r,ll,rr,v);
    		pushup(rt);
    	}
    	
    	int query(int rt,int l,int r,int ql,int qr)
    	{
    		if(ql>qr) return inf;
    		if(l>=ql&&r<=qr) return val[rt];
    		pushdown(rt);
    		int mid=(l+r)>>1;
    		int res=inf;
    		if(ql<=mid) res=min(res,query(rt<<1,l,mid,ql,qr));
    		if(mid<qr) res=min(res,query(rt<<1|1,mid+1,r,ql,qr));
    		return res;
    	}
    	
    	void work()
    	{
    		ios::sync_with_stdio(false);
    		cin>>n>>k;k++;
    		for(int i=2;i<=n;i++) cin>>d[i];
    		for(int i=1;i<=n;i++) cin>>c[i];
    		for(int i=1;i<=n;i++) cin>>s[i];
    		for(int i=1;i<=n;i++) cin>>w[i];
    		n++;w[n]=d[n]=inf;
    		
    		for(int i=1;i<=n;i++)
    		{
    			lef[i]=lower_bound(d+1,d+n+1,d[i]-s[i])-d;
    			rig[i]=lower_bound(d+1,d+n+1,d[i]+s[i])-d;
    			if(d[rig[i]]>d[i]+s[i]) rig[i]--;
    			pos[rig[i]].push_back(i);
    		} 
    		
    		for(int i=1;i<=k;i++)
    		{
    			if(i==1)
    			{
    				int res=0;
    				for(int j=1;j<=n;j++)
    				{
    					f[j]=res+c[j];
    					for(int l=0;l<pos[j].size();l++) res+=w[pos[j][l]];
    				}
    				ans=f[n];
    			}
    			else
    			{
    				build(1,1,n);
    				for(int j=1;j<=n;j++)
    				{
    					f[j]=query(1,1,n,1,j-1)+c[j];
    					for(int l=0;l<pos[j].size();l++) if(lef[pos[j][l]]>1) update(1,1,n,1,lef[pos[j][l]]-1,w[pos[j][l]]);	
    				}
    				ans=min(ans,f[n]);
    			}
    		}
    		cout<<ans<<endl;
    	
    	}
    
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
    
  • 相关阅读:
    Docker优势
    jdk-tomcat-jenkens 安装
    SQL-2--TRIGGER
    边工作边刷题:70天一遍leetcode: day 92
    边工作边刷题:70天一遍leetcode: day 39
    边工作边刷题:70天一遍leetcode: day 96
    边工作边刷题:70天一遍leetcode: day 1
    边工作边刷题:70天一遍leetcode: day 94
    边工作边刷题:70天一遍leetcode: day 95
    边工作边刷题:70天一遍leetcode: day 97
  • 原文地址:https://www.cnblogs.com/youth518/p/13851046.html
Copyright © 2020-2023  润新知