【NOIP_模拟题】地形剖面图

这篇博客介绍了NOIP竞赛中关于地形剖面图的模拟题,涉及到线段树数据结构的应用。文章详细阐述了20分、50分、100分算法,重点讲解了如何利用线段树进行区间修改和询问操作,特别是应对取负操作的双lazy标记策略。此外,还讨论了维护最长上升地势的方法以及在处理加减和取负操作时如何原地更新。最后,给出了样例输入和输出,以及代码实现。
摘要由CSDN通过智能技术生成

【数据资源】链接:http://pan.baidu.com/s/1hrPamJa 密码:uaec
【题目名称】地形剖面图
【时间限制】1000ms
【空间限制】128M
【题目描述】
公元XXXX年,人类进入了宇宙纪元。为了开发地质活动十分活跃的X星球上的某段长度为n千米的区域,你整理得到了该区域相关的地形剖面图信息。信息包括:

1.初始状态:
n个整数,其中第i个数表示该区域第(i-1)~i千米的平均海拔高度(单位:米)。这也意味着,这份地形剖面图被平分为了n段,每一段用一个整数来表示平均高度。而每一段是地形图的最小单位,每一段内部更具体的高度变化我们无从得知,也并不关心。

2.P次地质变化记录:
格式(T,L,R,D).表示公元T年,第L~R段地壳发生变化。D>0表示地壳上升了D米,D<0表示地壳下降了|D|米。而D=0意味着地壳发生了重大改变:第L~R段内每一段地壳高度都变为了原来的相反数。

数据保证,相同年份的地质变化记录所涵盖的区间不会有交集.

你将这些信息录入了程序,现在你要查询Q个问题(T,L,R),表示询问公元T年末,第L~R段内的上升地势的最长长度。上升地势是指一段区域内的海拔高度严格单调递增(按从左到右的顺序,这n段区域的编号顺序也是从左到右的)。

[输入格式]
第一行,三个正整数n,P,Q;
第二行,n个整数,表示地形图的初始状态(即T=0时);
接下来P行,每行四个整数,T,L,R,D,表示地质变化记录,其中T>=0,1<=L<=R<=n;
接下来Q行,每行三个整数,T,L,R,表示询问,其中T>=0,1<=L<=R<=n.

[输出格式]
共Q行,第i行表示第i个询问的答案。

样例输入
6 3 3
3 4 6 5 2 1
5 3 4 -2
6 2 6 0
8 3 5 6
3 1 5
6 2 6
9 2 5
样例输出
3
4
4
样例说明
第0年地形:3,4,6,5,2,1.
第5年地形:3,4,4,3,2,1.
第6年地形:3,-4,-4,-3,-2,-1.
第8年地形:3,-4,2,3,4,-1.
第3年询问:3,4,6,5,2,1.
第6年询问:3,-4,-4,-3,-2,-1.
第9年询问:3,-4,2,3,4,-1.
粗体部分表示所询问区间的最长上升地势
【数据范围】
对于20分的数据,1<=n,P,Q<=3000.
对于另30分的数据,1<=n,P,Q<=50000,D不为0.
对于100分的数据,1<=n,P,Q<=50000,T为非负整数.
所有输入输出保证在[-2000000000,2000000000]范围内.
任何一段区域的高度始终在[-2000000000,2000000000]范围内.

题解

20分算法

直接模拟.需要注意的是,求最长上升地势并不需要动规,直接计数即可,但很意外的是,此题在实际测试的过程中,有不少参考者使用动规进行求解,平添了不少的麻烦。

主要的麻烦在于要对记录和询问进行排序。
两种写法,二选一:
1.将两种操作合在一起排序,并加以标记;
2.两种操作分开写,并分别用pos1,pos2来记录两个数组讨论的到的位置。

参考代码:

#include<cstdio>
#include<algorithm>
using namespace std; 
#define MAXN 100000
int H[MAXN],n,P,Q;
int c[MAXN],L[MAXN],R[MAXN],D[MAXN],T[MAXN];
int cc[MAXN],l[MAXN],r[MAXN],t[MAXN];
bool cmp1(int a,int b)
{
    return T[a]<T[b];
}
bool cmp2(int a,int b)
{
    return t[a]<t[b];
}
int ANS[MAXN]; 
int main()
{
    freopen("map.in","r",stdin);
    freopen("map.out","w",stdout);
    scanf("%d%d%d",&n,&P,&Q);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&H[i]);
    }
    for(int i=1;i<=P;i++)
    {
        scanf("%d%d%d%d",&T[i],&L[i],&R[i],&D[i]);
        c[i]=i;
    }
    sort(c+1,c+1+P,cmp1);
    for(int i=1;i<=Q;i++)
    {
         scanf("%d%d%d",&t[i],&l[i],&r[i]);
         cc[i]=i;
    }
    sort(cc+1,cc+1+Q,cmp2);
    int pos=1;
    for(int i=1;i<=Q;i++)
    {
        int I=cc[i];
        while(pos<=P&&T[c[pos]]<=t[I])
        {
            for(int s=L[c[pos]];s<=R[c[pos]];s++)
            {
                if(D[c[pos]]!=0)
                {
                    H[s]+=D[c[pos<
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值