「雅礼集训 2017 Day2」水箱

题目链接

题意分析

我们用\(f[i][j]\)表示当前到达第\(i\)个位置水位高度为\(j\)的答案

如果那么\(h[i]\)\(i\)\(i+1\)之间的支柱高度

那么如果\(j≤h[i]\)的话

\(f[i+1][0...h[i]]=max\{f[i][0...h[i]]\}\)

否则的话 直接让\(f[i+1][j]=f[i][j]\)

发现第二种可以直接继承

第一种可以区间求\(max\)然后区间\(max\)覆盖

使用线段树维护

同时满足限制的话使用区间加

CODE:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<deque>
#include<vector>
#include<ctime>
#define ll long long
#define inf 0x7fffffff
#define N 500008
#define IL inline
#define M 608611
#define D double
#define ull unsigned long long
#define R register
using namespace std;
template<typename T>IL void read(T &_)
{
    T __=0,___=1;char ____=getchar();
    while(!isdigit(____)) {if(____=='-') ___=0;____=getchar();}
    while(isdigit(____)) {__=(__<<1)+(__<<3)+____-'0';____=getchar();}
    _=___ ? __:-__;
}
/*-------------OI使我快乐-------------*/
int T,n,m,cnt,tot;
int num[M],res[M],tre[M<<1],tag_cdy[M<<1],tag_wzy[M<<1];
vector<int> cdy[M],wzy[M];
IL void down(int si)
{
    if(!tag_cdy[si]&&!tag_wzy[si]) return;
    int d1=tag_cdy[si],d2=tag_wzy[si];
    tag_cdy[si<<1]+=d1;
    tag_cdy[si<<1|1]+=d1;
    tag_wzy[si<<1]=max(tag_wzy[si<<1]+d1,d2);
    tag_wzy[si<<1|1]=max(tag_wzy[si<<1|1]+d1,d2);   
    tre[si<<1]=max(tre[si<<1]+d1,d2);
    tre[si<<1|1]=max(tre[si<<1|1]+d1,d2);
    tag_cdy[si]=tag_wzy[si]=0;
}
IL void add(int si,int lenow,int rinow,int le,int ri,int d)
{
    if(le>ri) return;   
    if(lenow==le&&ri==rinow)
    {
        tre[si]+=d;
        tag_cdy[si]+=d;
        tag_wzy[si]+=d;
        return;
    }
    down(si);
    int mid=(lenow+rinow)>>1;
    if(ri<=mid) add(si<<1,lenow,mid,le,ri,d);
    else if(mid<le) add(si<<1|1,mid+1,rinow,le,ri,d);
    else add(si<<1,lenow,mid,le,mid,d),add(si<<1|1,mid+1,rinow,mid+1,ri,d);
    tre[si]=max(tre[si<<1],tre[si<<1|1]);   
}
IL void update(int si,int lenow,int rinow,int le,int ri,int d)
{
    if(le>ri) return;
//  printf("now at TREE is %d %d (%d %d)\n",lenow,rinow,le,ri);
    if(lenow==le&&rinow==ri)
    {
        tre[si]=max(tre[si],d);
        tag_wzy[si]=max(tag_wzy[si],d);
        return;
    }
    down(si);
    int mid=(lenow+rinow)>>1;
    if(ri<=mid) update(si<<1,lenow,mid,le,ri,d);
    else if(mid<le) update(si<<1|1,mid+1,rinow,le,ri,d);
    else update(si<<1,lenow,mid,le,mid,d),update(si<<1|1,mid+1,rinow,mid+1,ri,d);
    tre[si]=max(tre[si<<1],tre[si<<1|1]);
}
IL int qury(int si,int lenow,int rinow,int le,int ri)
{
    if(le>ri) return -inf;
//  printf("now at TREE is %d %d (%d %d)\n",lenow,rinow,le,ri); 
    if(lenow==le&&rinow==ri) return tre[si];
    down(si);
    int mid=(lenow+rinow)>>1;
    if(ri<=mid) return qury(si<<1,lenow,mid,le,ri);
    else if(mid<le) return qury(si<<1|1,mid+1,rinow,le,ri);
    else return max(qury(si<<1,lenow,mid,le,mid),qury(si<<1|1,mid+1,rinow,mid+1,ri));   
}
int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    read(T);
    while(T--)
    {
        memset(tre,0,sizeof tre);
        memset(tag_cdy,0,sizeof tag_cdy);
        memset(tag_wzy,0,sizeof tag_wzy);   
        memset(res,0,sizeof res);   
        read(n);read(m);res[tot=1]=inf;cnt=0;
        for(R int i=1;i<n;++i) read(num[i]),res[++tot]=num[i];
        for(R int i=1;i<=n;++i) cdy[i].clear(),wzy[i].clear();
        for(R int i=1,x,y,z;i<=m;++i)
        {
            read(x);read(y);read(z);
            if(!z) cdy[x].push_back(y);
            else wzy[x].push_back(y);
            res[++tot]=y;res[++tot]=y+1;
        }
        sort(res+1,res+tot+1);cnt=unique(res+1,res+tot+1)-res-1;
        for(R int i=1;i<n;++i) num[i]=lower_bound(res+1,res+cnt+1,num[i])-res;
        for(R int i=1;i<=n;++i) sort(cdy[i].begin(),cdy[i].end()),sort(wzy[i].begin(),wzy[i].end());
//      puts("now now now");
        for(R int i=1;i<=n;++i)
        {
            for(R int j=0;j<(int)cdy[i].size();++j)
            {
//              puts("now okoko");
                int now=lower_bound(res+1,res+cnt+1,cdy[i][j])-res;
                add(1,1,cnt,1,now,1);
//              puts("now okoko have");
            }
            for(R int j=0;j<(int)wzy[i].size();++j)
            {
//              puts("now okokookokoookoo");
                int now=lower_bound(res+1,res+cnt+1,wzy[i][j])-res;
                add(1,1,cnt,now+1,cnt,1);
//              puts("now okoko havehave");             
            }
            if(i==n) break;
//          puts("acsese");
            int tmp=qury(1,1,cnt,1,num[i]);
//          puts("sdfjsdhfj");
            update(1,1,cnt,1,num[i],tmp);
//          puts("weihjisdhgiuwe");
        }
        printf("%d\n",tre[1]);
    }
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

HEOI 2019 RP++

转载于:https://www.cnblogs.com/LovToLZX/p/10617726.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值