Codeforces Gym 100513F F. Ilya Muromets 线段树

F. Ilya Muromets

Time Limit: 20 Sec

Memory Limit: 256 MB

题目连接

http://codeforces.com/gym/100513/problem/F

Description

I

Ilya Muromets is a legendary bogatyr. Right now he is struggling against Zmej Gorynych, a dragon with n heads numbered from 1 to nfrom left to right.

Making one sweep of sword Ilya Muromets can cut at most k contiguous heads of Zmej Gorynych. Thereafter heads collapse getting rid of empty space between heads. So in a moment before the second sweep all the heads form a contiguous sequence again.

As we all know, dragons can breathe fire. And so does Zmej Gorynych. Each his head has a firepower. The firepower of the i-th head isfi.

Ilya Muromets has time for at most two sword sweeps. The bogatyr wants to reduce dragon‘s firepower as much as possible. What is the maximum total firepower of heads which Ilya can cut with at most two sword sweeps?

Input

The first line contains a pair of integer numbers n and k (1 ≤ n, k ≤ 2·105) — the number of Gorynych‘s heads and the maximum number of heads Ilya can cut with a single sword sweep. The second line contains the sequence of integer numbers f1, f2, ..., fn(1 ≤ fi ≤ 2000), where fi is the firepower of the i-th head.

Output

Print the required maximum total head firepower that Ilya can cut.

Sample Input

8 2
1 3 3 1 2 3 11 1

Sample Output

20

HINT

题意

一个人可以砍两刀,每刀可以消去连续的K个数,然后问你两刀最多能砍下数的和是多少

题解:

线段树,枚举这一块,然后除了这一块的其他块都是可以选择的

查询区间最大值就好了

代码

#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <typeinfo>
#include <fstream>
#include <map>
#include <stack>
typedef long long ll;
using namespace std;
//freopen("D.in","r",stdin);
//freopen("D.out","w",stdout);
#define sspeed ios_base::sync_with_stdio(0);cin.tie(0)
#define test freopen("test.txt","r",stdin)
const int maxn=2025001;
#define mod 1000000007
#define eps 1e-9
const int inf=0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3fLL;
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
//**************************************************************************************
struct node
{
    int l,r,ma,mi;
}a[maxn];
int d[maxn];
void build(int x,int l,int r)
{
    a[x].l=l,a[x].r=r;
    a[x].ma=-inf,a[x].mi=inf;
    if(l==r)
    {
        a[x].ma=d[l];
        a[x].mi=d[l];
        return;
    }
    else
    {
        int mid=(l+r)>>1;
        build(x<<1,l,mid);
        build(x<<1|1,mid+1,r);
        a[x].ma=max(a[x<<1].ma,a[x<<1|1].ma);
        a[x].mi=min(a[x<<1].mi,a[x<<1|1].mi);
    }
}
int query1(int x,int st,int ed)
{
    int l=a[x].l,r=a[x].r;
    if(st<=l&&r<=ed)
        return a[x].mi;
    else
    {
        int mid=(l+r)>>1;
        int mi1=inf,mi2=inf;
        if(st<=mid)
            mi1=query1(x<<1,st,ed);
        if(ed>mid)
            mi2=query1(x<<1|1,st,ed);
        return min(mi1,mi2);
    }
}

int query2(int x,int st,int ed)
{
    int l=a[x].l,r=a[x].r;
    if(st<=l&&r<=ed)
        return a[x].ma;
    else
    {
        int mid=(l+r)>>1;
        int mi1=-inf,mi2=-inf;
        if(st<=mid)
            mi1=query2(x<<1,st,ed);
        if(ed>mid)
            mi2=query2(x<<1|1,st,ed);
        return max(mi1,mi2);
    }
}
int aa[maxn];
int dp[maxn];
int sum=0;
int main()
{
    int n=read(),k=read();
    for(int i=1;i<=n;i++)
        aa[i]=read();
    for(int i=1;i<=n;i++)
        sum=sum+aa[i];
    for(int i=1;i<=k;i++)
        dp[i]+=aa[i]+dp[i-1];
    for(int i=k+1;i<=n;i++)
        dp[i]=dp[i-1]+aa[i]-aa[i-k];
    if(2*k>=n)
    {
        cout<<sum<<endl;
        return 0;
    }
    int ans=0;
    for(int i=1;i<=n-k+1;i++)
        d[i]=dp[k-1+i];
    build(1,1,n-k+1);
    for(int i=1;i<=n-k+1;i++)
    {
        if(i>k)
        {
            ans=max(ans,d[i]+query2(1,1,i-k));
        }
        else
            ans=max(ans,d[i]);
    }
    cout<<ans<<endl;
}
时间: 2024-08-24 12:18:20

Codeforces Gym 100513F F. Ilya Muromets 线段树的相关文章

GYM 101350 F. Monkeying Around(线段树 or 思维)

F. Monkeying Around time limit per test 2.0 s memory limit per test 256 MB input standard input output standard output When the monkey professor leaves his class for a short time, all the monkeys go bananas. N monkeys are lined up sitting side by sid

codeforces 446C DZY Loves Fibonacci Numbers 线段树

假如F[1] = a, F[2] = B, F[n] = F[n - 1] + F[n - 2]. 写成矩阵表示形式可以很快发现F[n] = f[n - 1] * b + f[n - 2] * a. f[n] 是斐波那契数列 也就是我们如果知道一段区间的前两个数增加了多少,可以很快计算出这段区间的第k个数增加了多少 通过简单的公式叠加也能求和 F[n]  = f[n - 1] * b + f[n - 2] * a F[n - 1] = f[n - 2] * b + f[n - 3] * a ..

codeforces 444 C. DZY Loves Colors(线段树)

题目大意: 1 l r x操作 讲 [l,r]上的节点涂成x颜色,并且每个节点的值都加上 |y-x| y为涂之前的颜色 2 l r  操作,求出[l,r]上的和. 思路分析: 如果一个区间为相同的颜色.那么我们才可以合并操作. 所以我们之前找相同的区间就好. 但是问题是如何合并操作. 那么我们定义一个val  表示这个区间每个位置上应该加上的值. pushdown 的时候这个值是可以相加的. #include <cstdio> #include <iostream> #includ

HDU 4902 Nice boat 2014杭电多校训练赛第四场F题(线段树区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4902 解题报告:输入一个序列,然后有q次操作,操作有两种,第一种是把区间 (l,r) 变成x,第二种是把区间 (l,r) 中大于x的数跟 x 做gcd操作. 线段树区间更新的题目,每个节点保存一个最大和最小值,当该节点的最大值和最小值相等的时候表示这个区间所有的数字都是相同的,可以直接对这个区间进行1或2操作, 进行1操作时,当还没有到达要操作的区间但已经出现了节点的最大值跟最小值相等的情况时,说明

Codeforces 444C DZY Loves Colors 水线段树

题目链接:点击打开链接 水.. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <math.h> #include <set> #include <vector> #include <map> using namespace std; #define ll long long #defi

CodeForces - 383C Propagating tree(dfs + 线段树)

题目大意: 给出一棵树,树上每个节点都有权值,然后有两个操作. 1 x val 在结点x上加上一个值val,x的儿子加上 -val,x的儿子的儿子加上 - (-val),以此类推. 2 x 问x节点的值. 思路分析: 每个节点上加值都是给自己的儿子节点加,而且这个是颗树. 比如样例上的,如果你给node 1加一个值,那么五个节点都加. 再给node 2加个值,2的儿子节点也加了,之前给1加的值也要加到2号节点的儿子. 所以你会发现节点的儿子会存在一个从属的关系. 这样的话,我们可以把所有节点从新

codeforces Beta Round #19 D. Point (线段树 + set)

题目大意: 对平面上的点进行操作. add x y 在 (x,y )上加一个点. remove x y 移除 (x,y)上的点. find x y 求出在(x,y)右上角离他最近的点,优先级是靠左,靠下. 思路分析: find 操作 比较麻烦. 要保证x大的同时还要确保x最小,而且该x上还要有点. 这样要找大的时候要小的,就是在线段树上选择性的进入左子树还是右子树. 所以核心就是,用set维护叶子节点. 然后查找的时候去叶子节点找,如果这个叶子节点有蛮子的 x y  就输出,否则回溯去另外一个子

Nastya Hasn&#39;t Written a Legend(Codeforces Round #546 (Div. 2)E+线段树)

题目链接 传送门 题面 题意 给你一个\(a\)数组和一个\(k\)数组,进行\(q\)次操作,操作分为两种: 将\(a_i\)增加\(x\),此时如果\(a_{i+1}<a_i+k_i\),那么就将\(a_{i+1}\)变成\(a_i+k_i\),如果\(a_{i+2}<a_i+k_i\),则将\(a_{i+2}\)变成\(a_{i+1}+k_{i+1}\),以此类推. 查询\(\sum\limits_{i=l}^{r}a_i\). 思路 我们首先存下\(k\)数组的前缀和\(sum1\),

Atcoder ABC158 F - Removing Robots 线段树+选集合类dp

Atcoder ABC158 F - Removing Robots 线段树+dp 题意 一条直线上有机器人,每个机器人有一个激活后行进值D[i],当激活它时,它就会向x轴方向走D[i]距离.进行后它就会离开坐标轴.激活有两种方式,一种是手动激活,一种是当一个机器人在激活状态时的行进距离[x[i],x[i]+D[i])注意右开区间,碰到了别的机器人,那个被碰的机器人就会被激活.同时它如果碰到了别的也会激活别的,连锁反应.问你可以任意选择任意个机器人激活,激活后剩余机器人的集合有多少种 思路 这种