扶桑号战列舰(差分/笛卡尔树)

                                                  问题 N: 扶桑号战列舰

                                               时间限制: 1 Sec  内存限制: 128 MB  Special Judge
                                                                       提交: 283  解决: 110
                                                                    [提交] [状态] [命题人:admin]

题目描述

众所周知,一战过后,在世界列强建造超无畏级战列舰的竞争之中,旧日本海军根据“个舰优越主义”,建造了扶桑级战列舰,完工时为当时世界上武装最为强大的舰只。
同时,扶桑号战列舰也是舰岛最为科幻的战列舰。
当然,要建造这样的舰船,科技水平是必须的。
同样众所周知的是,德意志科学技术天下第一,所以IJN的司令官从德国学来了一种先进的建船方法。
一只战舰横过来可以看做一个长度为n的序列,每个位置有一个数ai表示这个位置设计的高度。这种先进的造船技术可以每次将一个区间[l,r]内的所有位置高度都+1,求到达最终设计状态的最少操作次数。
如果你不能及时完成的话,IJN司令官会奖励你去参加苏里高海战。

 

输入

第一行包含一个整数n,表示序列的长度。
第二行包含n个非负整数a1,a2,a3,…,an,表示最终的状态。

 

输出

输出的第一行是一个正整数m,表示最少的操作次数。
接下来m行每行两个正整数li,ri,表示一次操作。
你需要保证1≤li≤ri≤n。
保证最少次数m≤105,输出可以以任意顺序输出。

样例输入

6
2 3 3 3 3 3

样例输出

6
2 3 3 3 3 3

提示

 

 

 

 

                                                                                  [提交][状态]

差分

题解:

差分数组

假如现在对数列中区间[L,R]上的数加上x,第一个受影响的差分数组中的元素为f[L],即令f[L]+=x,那么后面数列元素在计算过程中都会加上x;最后一个受影响的差分数组中的元素为f[R],所以令f[R+1]-=x,即可保证不会影响到R以后数列元素的计算。这样我们不必对区间内每一个数进行处理,只需处理两个差分后的数即可;

所以在差分数组中值大于0表示左边界,小于等于0表示右边界,然后通过栈进行匹配即可

/*
Niubility_n
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
int l[maxn];
int a[maxn],d[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),d[i]+=a[i]-a[i-1];
    ll ans=0;
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        if(d[i]>=0)ans+=d[i];
    }
    printf("%lld\n",ans);
    for(int i=1;i<=n+1;i++)
    {
        if(d[i]>0)
        {
            for(int j=1;j<=d[i];j++)
            {
                l[cnt++]=i;
            }
        }
        else
        {
            for(int j=1;j<=(a[i-1]-a[i]);j++)
            {
                printf("%d %d\n",l[cnt-1],i-1);
                cnt--;
            }
        }
    }
    return 0;
}

笛卡尔树

题解

找从0,到 [1,n]的最小值,然后跳到次小值,继续找,这样可以构造一个小根堆的笛卡尔树。

那么根节点就是[1,n]的最小值,左儿子就是[1,root-1]的最小值,右儿子就是[root+1,n]的最小值

所以可以递归处理左右区间,因为这个递归函数相当于遍历一棵笛卡尔树,所以时间复杂度是O(n)

/*
Niubility_n
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=2e5+10;
int n;
int val[maxn];
int Stack[maxn],top;
int l[maxn],r[maxn],root;
void Insert(int i)
{
    while(top && val[Stack[top]]>=val[i])l[i]=Stack[top--];

    if(top)r[Stack[top]]=i;
    Stack[++top]=i;
}
int ansl[maxn],ansr[maxn],ans[maxn],cnt;
void dfs(int root,int L,int R,int last)
{
    if(L>R)return ;
    ansl[cnt]=L,ansr[cnt]=R,ans[cnt++]=val[root]-last;
    dfs(l[root],L,root-1,val[root]);
    dfs(r[root],root+1,R,val[root]);
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&val[i]);
        Insert(i);
    }
    while(top)root=Stack[top--];//找根节点 栈中的最后一个元素就是根节点因为维护的是最小值

    dfs(root,1,n,0);
    int anss=0;
    for(int i=0;i<cnt;i++)anss+=ans[i];
    printf("%d\n",anss);
    for(int i=0;i<cnt;i++)
    {
        while(ans[i])printf("%d %d\n",ansl[i],ansr[i]),ans[i]--;
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值