zoukankan      html  css  js  c++  java
  • bzoj4094[Usaco2013 Dec]Optimal Milking最优挤奶

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4094

    题目大意:

    约翰有N 台挤奶机器,这些机器排成了一条直线,其中第i台机器工作效率是Ai,也就是说工作一天可以产出Ai。约翰将会开动这些机器工作Q 天。每天一早,约翰一定会维修一台机器。在第i 天早上,他维修的是第Ti 台机器,经过维修之后,这台机器的工作效率将会变成Di。在任何时候,位置相邻的两台机器都不能同时工作。请问约翰每天应该选择开动哪些机器,才能让这Q 天的总产出之和最大?

    题解:

    线段树

    脖子上没有东西的我天真的以为直接每天取奇数位的或者偶数位的机器开,维护两个变量:和&开奇数位机器的和。但是直到我只过了两个点才发现明显的错啊qwq反例还是容易找到的[尽管我找到的反例其实并不是反例= =不管反正知道错了。

    所以我的线段树后来就维护了四个变量,左端点取右端点不取,左端点不取右端点取,两个端点都取/不取的最大值。

    方便不打错就直接开了个二维小数组~

    方便记答案还多开了个变量mx,就是上面那四个东西中的最大值。。

    好像知道怎么去维护就应该会做了吧嗯。

    想了还不会再看看我那长得丑的代码↓

    ([0][0]就表示左右端点都不取..依此类推)

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    #define maxn 201000
    
    struct tree
    {
    	int l,r,lc,rc;LL a[2][2],mx;
    }tr[maxn];int tlen;
    LL mymax(LL x,LL y){return (x>y)?x:y;}
    void bt(int l,int r)
    {
    	tlen++;int now=tlen;
    	tr[now].l=l;tr[now].r=r;
    	tr[now].lc=tr[now].rc=-1;
    	memset(tr[now].a,0,sizeof(tr[now].a));
    	tr[now].mx=0;
    	if (l<r)
    	{
    		int mid=(l+r)>>1;
    		tr[now].lc=tlen+1;bt(l,mid);
    		tr[now].rc=tlen+1;bt(mid+1,r);
    	}
    }
    void updata(int now,int lc,int rc)//四种情况分别更新
    {
    	tr[now].a[0][0]=mymax(tr[lc].a[0][1]+tr[rc].a[0][0],tr[lc].a[0][0]+tr[rc].a[1][0]);
    	tr[now].a[1][0]=mymax(tr[lc].a[1][1]+tr[rc].a[0][0],tr[lc].a[1][0]+tr[rc].a[1][0]);
    	tr[now].a[0][1]=mymax(tr[lc].a[0][1]+tr[rc].a[0][1],tr[lc].a[0][0]+tr[rc].a[1][1]);
    	tr[now].a[1][1]=mymax(tr[lc].a[1][1]+tr[rc].a[0][1],tr[lc].a[1][0]+tr[rc].a[1][1]);	
    }
    void change(int now,int x,LL k)
    {
    	if (tr[now].l==tr[now].r)
    	{
    		tr[now].a[1][1]=k;
    		tr[now].mx=k;
    		return;
    	}
    	int mid=(tr[now].l+tr[now].r)>>1,lc=tr[now].lc,rc=tr[now].rc;
    	if (x<=mid) change(lc,x,k);
    	else change(rc,x,k);
    	updata(now,lc,rc);
    	tr[now].mx=mymax(tr[now].a[0][0],tr[now].a[0][1]);
    	tr[now].mx=mymax(tr[now].mx,mymax(tr[now].a[1][0],tr[now].a[1][1]));
    }
    int main()
    {
    	//freopen("optmilk.in","r",stdin);
    	//freopen("optmilk.out","w",stdout);
    	int n,q,i;LL ans,x,c;
    	scanf("%d%d",&n,&q);
    	tlen=0;bt(1,n);
    	for (i=1;i<=n;i++)
    	{
    		scanf("%lld",&x);
    		change(1,i,x);
    	}ans=0;
    	while (q--)
    	{
    		scanf("%lld%lld",&x,&c);
    		change(1,x,c);
    		ans+=tr[1].mx;
    	}printf("%lld
    ",ans);
    	return 0;
    }


  • 相关阅读:
    如何把新加的分区挂载到指定目录下
    怎样通过U盘安装启动Centos6.8
    Redis 单机安装【一】
    Linux漏洞扫描工具【lynis】
    mysql 主从 重新同步
    Centos 6.8下安装oracle10g数据库、
    监控服务supervisor服务的安装及使用
    制作c#桌面应用程序 安装程序 卸载程序
    Microsoft Visual SourceSafe 2005 服务端安装配置过程以及出现的问题,以及解决方法!
    .NET中的CSV导入导出
  • 原文地址:https://www.cnblogs.com/Euryale-Rose/p/6527835.html
Copyright © 2011-2022 走看看