bzoj4094 && luogu3097 最优挤奶

题目大意:

给定n个点排成一排,每个点有一个点权,有m次修改,每次改变某个点的点权并将最大点独立集计入答案,输出最终的答案

其中\(n\le 40000\ , \ m\le 50000\)

QWQ说实话,一开始看这个题,没啥思路呀

后来看了题解才知道是线段树

我们考虑对一个区间,我们只需要关心左右节点是否取,就可以从小的区间更新大区间。

从而实现线段树的区间合并了

QWQ我们定义

\(f[i].both\)表示左右边界都取

\(f[i].left\)表示只取左边界

\(f[i].right\)表示只取右边界

\(f[i].neither\)表示左右边界都不取

对于每种情况,我们分开讨论

首先定义\(l=2*root,r=2*root+1\)

对于\(f[root].both\)

\(f[root].both=max(f[l].left+max(f[r].both,f[r].right),f[l].both+f[r].right);\)

也就是如果左边只取左,右边可以都取或者只取右

如果左边都取,那么右边只能取右了(因为中间的左右区间的交界处也是不能同时取到的)

对于\(f[root].right,f[root].left\)

\(f[root].left=max(f[l].left+max(f[r].neither,f[r].left),f[l].both+f[r].neither);\)

\(f[root].right=max(f[l].neither+max(f[r].right,f[r].both),f[l].right+f[r].right);\)

同样的方法,处理一下

而对于\(f[root].neither\)

\(f[root].neither=max(max(f[l].neither+f[r].neither,f[l].right+f[r].neither),f[r].left+f[l].neither)\)

然后考虑更新的部分话

将一个点权修改也就是重新更新那个节点的\(f[root].both\),然后将其他的清零。

最后更新就行

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>

using namespace std;

inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch==‘-‘) f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
  return x*f;
}

const int maxn = 40010;

struct Node{
    int left,right,both,neither;
};

Node f[4*maxn];
int n,a[maxn];
int m;
long long ans;

void up(int root)
{
    int l = 2*root,r=2*root+1;
    f[root].both=max(f[l].left+max(f[r].both,f[r].right),f[l].both+f[r].right);
    f[root].left=max(f[l].left+max(f[r].neither,f[r].left),f[l].both+f[r].neither);
    f[root].right=max(f[l].neither+max(f[r].right,f[r].both),f[l].right+f[r].right);
    f[root].neither=max(max(f[l].neither+f[r].neither,f[l].right+f[r].neither),f[r].left+f[l].neither);
}

void build(int root,int l,int r)
{
    if (l==r)
    {
        f[root].left=f[root].right=f[root].neither=0;
        f[root].both=a[l];
        return;
    }
    int mid = (l+r) >> 1;
    build(2*root,l,mid);
    build(2*root+1,mid+1,r);
    up(root);
}

void update(int root,int l,int r,int x,int p)
{
    if (l==r)
    {
        f[root].left=f[root].right=f[root].neither=0;
        f[root].both=p;
        return;
    }
    int mid =(l+r) >> 1;
    if (x<=mid) update(2*root,l,mid,x,p);
    if (x>mid) update(2*root+1,mid+1,r,x,p);
    up(root);
}

int main()
{
  n=read();m=read();
  for (int i=1;i<=n;i++) a[i]=read();
  build(1,1,n);
  for (int i=1;i<=m;i++)
  {
    int day,x;
    day=read(),x=read();
    update(1,1,n,day,x);
    long long tmp=max(f[1].left,max(f[1].right,max(f[1].both,f[1].neither)));
    ans+=tmp;
  }
  cout<<ans<<endl;
  return 0;
}

原文地址:https://www.cnblogs.com/yimmortal/p/10160677.html

时间: 2024-10-31 02:44:52

bzoj4094 && luogu3097 最优挤奶的相关文章

poj2112,最大流,最优挤奶方案

按图论列表上来说是基础题. 这道题是省赛之前过的,现在想再拿出来总结一下,感觉这个类型的题很经典. 题意不叙述了,就是有奶牛和机器,每台奶牛分配一个机器, 牛与牛.牛与机器.机器与机器之间都有一距离,求分配后的最大距离的最小值. 一开始没明白啥叫"最大距离的最小值",就是C头奶牛.K个挤奶器,C头奶牛若想到全部的挤奶器那里去需要一定的距离, C头奶牛当中某一头奶牛需要走的距离最大那这个距离便为最大值,要使这个最大值最小.(DT的题意) 这样子二分就好了,(又是二分,泥垢了),若根据mi

POJ 2112 Optimal Milking 最优挤奶方案 Floyd算法+二分查找+最大流

题目链接:POJ 2112 Optimal Milking Optimal Milking Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 12446   Accepted: 4494 Case Time Limit: 1000MS Description FJ has moved his K (1 <= K <= 30) milking machines out into the cow pastures among

P3097 [USACO13DEC]最优挤奶(线段树优化dp)

盲猜dp系列... 题意:给定序列,选了i就不能选与i相邻的两个,求最大值,带修改 蒟蒻在考场上10min打完以为只有两种情况的错解...居然能骗一点分... 先讲下当时的思路吧. f[i][0/1]表示第i台选不选的挤奶最大值,两个转移,水得不行. 考完之后在大佬的点播下才明白,这是一个类似独立集的东西. 但是这个数据范围绝对不是让我们跑最大独立集的,毕竟还要修改233... solution: 求和....单点修改...最大值....貌似能想到些什么..... 可爱的线段树..(一点都不可爱

poj 2112 最优挤奶方案

Optimal Milking Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 16550   Accepted: 5945 Case Time Limit: 1000MS Description FJ has moved his K (1 <= K <= 30) milking machines out into the cow pastures among the C (1 <= C <= 200) co

【BZOJ4094】[Usaco2013 Dec]Optimal Milking 线段树

[BZOJ4094][Usaco2013 Dec]Optimal Milking Description Farmer John最近购买了N(1 <= N <= 40000)台挤奶机,编号为1 ... N,并排成一行.第i台挤奶机每天能够挤M(i )单位的牛奶 (1 < =M(i) <=100,000).由于机器间距离太近,使得两台相邻的机器不能在同一天使用.Farmer Jo hn可以自由选择不同的机器集合在不同的日子进行挤奶.在D(1 < = D < = 50,00

BZOJ 1642: [Usaco2007 Nov]Milking Time 挤奶时间( dp )

水dp 先按开始时间排序 , 然后dp. dp( i ) 表示前 i 个时间段选第 i 个时间段的最优答案 , 则 dp( i ) = max( dp( j ) ) + w_i ( 0 < j < i ) , answer = max( dp( i ) ) ( 1 <= i <= m ) ------------------------------------------------------------------------------------------- #inclu

POJ 3616 Milking Time 挤奶问题,带权区间DP

题目链接:POJ 3616 Milking Time Milking Time Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4837   Accepted: 2034 Description Bessie is such a hard-working cow. In fact, she is so focused on maximizing her productivity that she decides to sc

【题解】Luogu P2889 [USACO07NOV]挤奶的时间Milking Time

Luogu P2889 [USACO07NOV]挤奶的时间Milking Time 题目描述 传送门Bessie is such a hard-working cow. In fact, she is so focused on maximizing her productivity that she decides to schedule her next N (1 ≤ N ≤ 1,000,000) hours (conveniently labeled 0..N-1) so that she

JVM原理讲解和调优

一.什么是JVM JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的. Java语言的一个非常重要的特点就是与平台的无关性.而使用Java虚拟机是实现这一特点的关键.一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码.而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译.Java语言使用Java虚拟机屏蔽了与具体平台相关的信息