首页 > 代码库 > BZOJ 3747 POI 2015 Kinoman 线段树

BZOJ 3747 POI 2015 Kinoman 线段树

题目大意:给出电影院的放映电影顺序,一个电影只有看过一次的时候会获得电影的权值。没看过或者看两次或以上都不能获得权值。问看连续区间的电影能够获得的最大权值是多少。


思路:利用线段树维护前缀和。将出现第一次的地方的权值加上那部电影的权值,第二次出现的时候权值减去那部电影的权值。枚举起点,先更新答案,然后在当前节点减去权值的二倍,然后再在下一次出现的地方加上权值(我感觉我没说明白,总之看代码吧。。。


CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 1000010
using namespace std;
#define LEFT (pos << 1)
#define RIGHT (pos << 1|1)
 
struct SegTree{
    long long _max,c;
}tree[MAX << 2];
 
int total,cnt;
int src[MAX],value[MAX];
int first[MAX],last[MAX],next[MAX];
 
inline void PushDown(int pos)
{
    if(tree[pos].c) {
        tree[LEFT]._max += tree[pos].c;
        tree[RIGHT]._max += tree[pos].c;
        tree[LEFT].c += tree[pos].c;
        tree[RIGHT].c += tree[pos].c;
        tree[pos].c = 0;
    }
}
 
inline void Modify(int l,int r,int x,int y,int c,int pos)
{
    if(l == x && y == r) {
        tree[pos]._max += c;
        tree[pos].c += c;
        return ;
    }
    PushDown(pos);
    int mid = (l + r) >> 1;
    if(y <= mid) Modify(l,mid,x,y,c,LEFT);
    else if(x > mid) Modify(mid + 1,r,x,y,c,RIGHT);
    else {
        Modify(l,mid,x,mid,c,LEFT);
        Modify(mid + 1,r,mid + 1,y,c,RIGHT);
    }
    tree[pos]._max = max(tree[LEFT]._max,tree[RIGHT]._max);
}
 
inline long long Ask(int l,int r,int x,int y,int pos)
{
    if(l == x && y == r)
        return tree[pos]._max;
    PushDown(pos);
    int mid = (l + r) >> 1;
    if(y <= mid) return Ask(l,mid,x,y,LEFT);
    if(x > mid)      return Ask(mid + 1,r,x,y,RIGHT);
    long long left = Ask(l,mid,x,mid,LEFT);
    long long right = Ask(mid + 1,r,mid + 1,y,RIGHT);
    return max(left,right);
}
 
int main()
{
    cin >> total >> cnt;
    for(int i = 0; i < MAX; ++i) next[i] = total + 1;
    for(int i = 1; i <= total; ++i) {
        scanf("%d",&src[i]);
        if(!first[src[i]]) {
            first[src[i]] = i;
            last[src[i]] = i;
        }
        else {
            next[last[src[i]]] = i;
            last[src[i]] = i;
        }
    }
    for(int i = 1; i <= cnt; ++i)
        scanf("%d",&value[i]);
    for(int i = 1; i <= cnt; ++i)
        if(first[i]) {
            Modify(1,total + 1,first[i],total + 1,value[i],1);
            Modify(1,total + 1,next[first[i]],total + 1,-value[i],1);
        }
    long long ans = 0;
    for(int i = 1; i <= total; ++i) {
        ans = max(ans,Ask(1,total,i,total,1));
        Modify(1,total + 1,i,total + 1,-value[src[i]],1);
        Modify(1,total + 1,next[i],total + 1,value[src[i]] << 1,1);
        Modify(1,total + 1,next[next[i]],total + 1,-value[src[i]],1);
    }
    cout << ans << endl;
    return 0;
}


BZOJ 3747 POI 2015 Kinoman 线段树