zoukankan      html  css  js  c++  java
  • BZOJ 3747: [POI2015]Kinoman( 线段树 )

    线段树...

    我们可以枚举左端点 , 然后用线段树找出所有右端点中的最大值 .

    -----------------------------------------------------------------------------------------

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
     
    #define rep( i , n ) for( int i = 0 ; i < n ; ++i )
    #define clr( x , c ) memset( x , c , sizeof( x ) )
    #define Rep( i , n ) for( int i = 1 ; i <= n ; ++i )
    #define M( l , r ) ( ( l + r ) >> 1 )
     
    using namespace std;
     
    typedef long long ll;
     
    const int maxn = 1000000 + 5;
     
    int L , R , v , n;
     
    struct Node {
    Node *lc , *rc;
    ll mx , v , add;
    Node() {
    mx = v = add = 0;
    lc = rc = NULL;
    }
    inline void Add( ll ad ) {
    add += ad;
    }
    inline void update() {
    if( lc ) 
    mx = max( lc -> mx , rc -> mx ) + add;
    else 
       mx =  (v += add ) , add = 0;
    }
    inline void pushdown() {
    lc -> Add( add );
    rc -> Add( add );
    add = 0;
    }
    } nodePool[ maxn << 1 ] , *pt = nodePool , *root;
     
    void build( Node* t , int l , int r ) {
    if( r > l ) {
       build( t -> lc = pt++ , l , M( l , r ) );
       build( t -> rc = pt++ , M( l , r ) + 1 , r );
    }
    t -> update();
    }
     
    // add
    void modify( Node* t , int l , int r ) {
    if( L <= l && r <= R )
    t -> Add( v );
    else {
    t -> pushdown();
    int m = M( l , r );
    L <= m ? modify( t -> lc , l , m ) : t -> lc -> update();
    m < R ? modify( t -> rc , m + 1 , r ) : t -> rc -> update();
    }
    t -> update();
    }
     
    int w[ maxn ];
     
    struct day {
    int f;
    day* next;
    day() {
    next = NULL;
    }
    } *head[ maxn ] , *last[ maxn ] , d[ maxn ];
     
    int main() {
    freopen( "test.in" , "r" , stdin );
    clr( last , 0 );
    int m;
    cin >> n >> m;
    build( root = pt++ , 1 , n );
    Rep( i , n ) {
    head[ i ] = d + i;
    scanf( "%d" , &head[ i ] -> f );
    }
    Rep( i , m )
       scanf( "%d" , w + i );
    for( int i = n ; i ; i-- ) {
    head[ i ] -> next = last[ head[ i ] -> f ];
    last[ head[ i ] -> f ] = head[ i ];
    }
    Rep( i , m ) if( last[ i ] ) {
    L = last[ i ] - d , R = last[ i ] -> next ? last[ i ] -> next - d - 1 : n;
    v = w[ i ];
    modify( root , 1 , n );
    }
    ll ans = 0;
    Rep( i , n ) {
    ans = max( ans , root -> mx );
    if( head[ i ] -> next ) {
    L = i , R = head[ i ] -> next - d - 1;
    v = -w[ head[ i ] -> f ];
    modify( root , 1 , n );
    L = head[ i ] -> next - d , v = w[ head[ i ] -> f ];
    if( head[ i ] -> next -> next )
       R = head[ i ] -> next -> next - d - 1;
    else 
       R = n;
    modify( root , 1 , n );
    } else {
    L = i , R = n , v = -w[ head[ i ] -> f ];
    modify( root , 1 , n );
    }
    }
    cout << ans << " ";
    return 0;
    }

      

    ----------------------------------------------------------------------------------------- 

    3747: [POI2015]Kinoman

    Time Limit: 60 Sec  Memory Limit: 128 MB
    Submit: 440  Solved: 165
    [Submit][Status][Discuss]

    Description

    共有m部电影,编号为1~m,第i部电影的好看值为w[i]。
    在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部。
    你可以选择l,r(1<=l<=r<=n),并观看第l,l+1,…,r天内所有的电影。如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值。所以你希望最大化观看且仅观看过一次的电影的好看值的总和。

    Input

    第一行两个整数n,m(1<=m<=n<=1000000)。
    第二行包含n个整数f[1],f[2],…,f[n](1<=f[i]<=m)。
    第三行包含m个整数w[1],w[2],…,w[m](1<=w[j]<=1000000)。

    Output

    输出观看且仅观看过一次的电影的好看值的总和的最大值。

    Sample Input

    9 4
    2 3 1 1 4 1 2 4 1
    5 3 6 6

    Sample Output

    15
    样例解释:
    观看第2,3,4,5,6,7天内放映的电影,其中看且仅看过一次的电影的编号为2,3,4。

    HINT

    Source

  • 相关阅读:
    点 多边形内外判断
    Winform获取js变量值
    软件和系统之间的微妙
    c# 读写json文件
    不规则图形重心
    c# winform 打开html界面(含引用外部文件js)
    c# GDI 画圆,可以调整大小等功能
    mysql 查找乱码数据
    类实例的拷贝
    Java 并发专题 :FutureTask 实现预加载数据 在线看电子书、浏览器浏览网页等
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/4637078.html
Copyright © 2011-2022 走看看