zoukankan      html  css  js  c++  java
  • luogu P2605 [ZJOI2010]基站选址 线段树优化dp

    LINK:基站选址

    md气死我了l达成1结果一直调

    显然一个点只建立一个基站 然后可以从左到右进行dp.

    (f_{i,j})表示强制在i处建立第j个基站的最小值。

    暴力枚举转移 复杂度(ncdot k^2)

    考虑如何求一个区间中的贡献 显然我们需要把每个点的左右给求出来 这个其实可以利用二叉堆来维护左端点/右端点。

    发现多次调用 考虑优化 利用邻接表即可。

    容易想到利用数据结构来优化。

    可以发现 不断向右的过程中只要把每个点的贡献在线段树上表达出来即可。

    这点很容易得到 不再赘述。

    最后预处理一下某个端点向右的代价 然后更新答案即可。

    code
    //#include<bitsstdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 2000000000
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define gc(a) scanf("%s",a+1)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define vep(p,n,i) for(RE int i=p;i<n;++i)
    #define pii pair<int,int>
    #define mk make_pair
    #define RE register
    #define P 1000000007
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define uint unsigned long long
    #define ui unsigned
    #define EPS 1e-8
    #define sq sqrt
    #define S second
    #define F first
    #define mod 1000000007
    #define l(x) t[x].l 
    #define r(x) t[x].r 
    #define sum(x) t[x].sum 
    #define tag(x) t[x].tag 
    #define zz p<<1
    #define yy p<<1|1
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        RE int x=0,f=1;RE char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    const int MAXN=20010,maxn=110;
    int n,k,len;
    int d[MAXN],c[MAXN],s[MAXN],w[MAXN];
    int f[MAXN][maxn];
    int L[MAXN],R[MAXN];
    int lin[MAXN],ver[MAXN],nex[MAXN];
    struct wy
    {
    	int l,r;
    	int sum;
    	int tag;
    }t[MAXN<<2];
    inline void add(int x,int y)
    {
    	ver[++len]=y;
    	nex[len]=lin[x];
    	lin[x]=len;
    }
    inline void build(int p,int l,int r,int x)
    {
    	l(p)=l;r(p)=r;tag(p)=0;
    	if(l==r){sum(p)=f[l][x];return;}
    	int mid=(l+r)>>1;
    	build(zz,l,mid,x);
    	build(yy,mid+1,r,x);
    	sum(p)=min(sum(zz),sum(yy));
    }
    inline void pushdown(int p)
    {
    	sum(zz)+=tag(p);
    	tag(zz)+=tag(p);
    	sum(yy)+=tag(p);
    	tag(yy)+=tag(p);
    	tag(p)=0;
    }
    inline void change(int p,int l,int r,int x)
    {
    	if(l<=l(p)&&r>=r(p)){sum(p)+=x;tag(p)+=x;return;}
    	int mid=(l(p)+r(p))>>1;
    	if(tag(p))pushdown(p);
    	if(l<=mid)change(zz,l,r,x);
    	if(r>mid)change(yy,l,r,x);
    	sum(p)=min(sum(zz),sum(yy));
    }
    inline int ask(int p,int l,int r)
    {
    	if(l<=l(p)&&r>=r(p))return sum(p);
    	int mid=(l(p)+r(p))>>1;
    	if(tag(p))pushdown(p);
    	if(r<=mid)return ask(zz,l,r);
    	if(l>mid)return ask(yy,l,r);
    	return min(ask(zz,l,r),ask(yy,l,r));
    }
    int main()
    {
    	//freopen("1.in","r",stdin);
    	get(n);get(k);int ans=0;
    	rep(2,n,i)get(d[i]);
    	rep(1,n,i)get(c[i]);
    	rep(1,n,i)
    	{
    		int get(x);
    		L[i]=lower_bound(d+1,d+1+n,d[i]-x)-d;
    		R[i]=upper_bound(d+1,d+1+n,d[i]+x)-d-1;
    		add(L[i],i);
    	}
    	int res=0;
    	rep(1,n,i)get(w[i]),ans+=w[i];
    	fep(n,1,j)
    	{
    		s[j]=res;
    		go(j)res+=w[tn];
    	}
    	len=0;res=0;
    	memset(lin,0,sizeof(lin));
    	rep(1,n,i)add(R[i],i);
    	rep(1,k,j)
    	{
    		if(j!=1)build(1,1,n,j-1);
    		rep(1,n,i)
    		{
    			if(j==1)
    			{
    				f[i][j]=c[i]+res;
    				for(int v=lin[i];v;v=nex[v])
    				{
    					int tn=ver[v];
    					res+=w[tn];
    				}
    			}
    			else
    			{
    				f[i][j]=ask(1,1,i)+c[i];
    				for(int v=lin[i];v;v=nex[v])
    				{
    					int tn=ver[v];
    					if(L[tn]>1)change(1,1,L[tn]-1,w[tn]);
    				}
    			}
    			ans=min(ans,f[i][j]+s[i]);
    		}
    	}
    	put(ans);return 0;
    }
    
  • 相关阅读:
    centos 6.5 查看、开启,关闭 端口
    centos 安装 nginx
    centos 安装 svn
    centos 安装 maven
    (转)不停止Nginx服务的情况下平滑变更Nginx配置
    记录1---python+linux+vim之while循环语句使用
    记录1---linux系统之创建用户,用户登录,查看用户名,切换用户登录,退出登录
    记录——Fiddler5.0 中文版 绿色免费版 汉化破解版安装
    fiddler笔记1---fiddler的安装 和 证书安装 以及 证书导出失败问题解决
    fiddler笔记2--fiddler工具界面的功能使用与介绍
  • 原文地址:https://www.cnblogs.com/chdy/p/13281497.html
Copyright © 2011-2022 走看看