• 【bzoj3747】Kinoman[POI2015](线段树)


      题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3747

      对于这种题,考虑固定区间的右端点为r,设区间左端点为l能取得的好看值总和为a[l],那么就相当于当r取不同取值时所有al的最大值。

      设last[i]表示第i部电影上一次出现的位置,当右端点r右移1位时,因为只有看了一遍的电影能获取好看值,所以能取得f[r]的好看值的al只能是在last[r]~r这个区间。因此每次右移时,last[last[r]]+1~last[r]减去w[f[r]],last[r]+1~r加上w[f[r]]。

      具体实现, 就是维护一个资瓷区间加与查询区间最大的线段树。

      代码(常数真大):

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<ctime>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    #define ll long long
    #define max(a,b) (a>b?a:b)
    #define min(a,b) (a<b?a:b)
    #define inf 1ll<<60
    ll read()
    {
        ll tmp=0; char c=getchar(),f=1;
        for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1;
        for(;'0'<=c&&c<='9';c=getchar())tmp=tmp*10+c-'0';
        return tmp*f;
    }
    using namespace std;
    struct point{
        ll delta,mx;
    }a[4000010];
    ll w[1000010];
    int f[1000010],last[1000010],pos[1000010];
    int n,m;
    void add(int now,int l,int r,int x,int y,ll k)
    {
        if(x<=l&&r<=y){
            a[now].delta+=k; a[now].mx+=k;
        }
        else{
            int mid=(l+r)>>1;
            if(x<=mid)add(now<<1,l,mid,x,y,k);
            if(mid<y)add(now<<1|1,mid+1,r,x,y,k);
            a[now].mx=max(a[now<<1].mx,a[now<<1|1].mx)+a[now].delta; 
        }
    }
    ll getmax(int now,int l,int r,int x,int y)
    {
        if(x<=l&&r<=y)return a[now].mx;
        else{
            ll tmp=-inf; int mid=(l+r)>>1;
            if(x<=mid)tmp=max(tmp,getmax(now<<1,l,mid,x,y));
            if(mid<y)tmp=max(tmp,getmax(now<<1|1,mid+1,r,x,y));
            return tmp+a[now].delta;
        }
    }
    int main()
    {
        int i;
        n=read(); m=read();
        last[0]=-1;
        for(i=1;i<=n;i++){
            f[i]=read();
            if(!pos[f[i]])last[i]=0;
            else last[i]=pos[f[i]];
            pos[f[i]]=i;
        }
        for(i=1;i<=m;i++)w[i]=read();
        ll ans=-inf;
        for(i=1;i<=n;i++){
            add(1,1,n,last[i]+1,i,w[f[i]]);
            if(~last[last[i]])add(1,1,n,last[last[i]]+1,last[i],-w[f[i]]);
            ans=max(ans,getmax(1,1,n,1,i));
        }
        printf("%lld
    ",ans);
    }
    bzoj3747
  • 相关阅读:
    notepad++ remove duplicate line
    notepad++ $ ^
    中文名: 交通事故责任认定, 英文名称: Traffic accident responsibility identification
    java 反射 获取Class对象的三种方式
    [转]java中byte转换int时为何与0xff进行与运算
    java中byte取值范围为什么是 -128到127
    bytes2HexString
    DBCS 从256开始
    android开发之使用拼音搜索汉字
    电脑故障,路由器及网络
  • 原文地址:https://www.cnblogs.com/quzhizhou/p/8308879.html
Copyright © 2020-2023  润新知