【CERC2015】【BZOJ4432】Greenhouse Growth

Description

你从计算机科学转向农业,你的新工作包括在一个地下温室种植向日葵。在温室中有n个排列在一条直线的向日葵植株,从左向右编号为1到n。有A、B2个照射器为向日葵的生长提供光和热,且照射器A、B分别放置在向日葵的左右两端。
每天只有1个照射器被打开,使所有向日葵转向光源,并使部分向日葵生长。向日葵会生长当且仅当其朝向的相邻植株比它更高,其每天的生长高度为1厘米。请注意,一个植株的生长将使其背后的植株立刻开始生长。
样例数据前三天的生长情况

你将被给出向日葵的初始高度和接下来m天的光照计划,请计算所有向日葵最终的高度。
Input

第一行有2个整n和m(1<= n, m <=300 000)——植株数和天数。
接下来一行包括n个整数h1, h2,… , hn (1 <= hk <=109)——从左到右向日葵的初始高度。
接下来一行包括一个仅含字母A/B长度为m的字符串——从第一天开始的光照计划。
Output

n个整数——从左到右每株向日葵最终的高度
Sample Input

6 5

4 3 5 3 6 6

BABAA

Sample Output

5 5 6 6 6 6
HINT

Source

一开始觉得是线段树,实际上链表模拟一下就行了..
搞标记记录一下A亮的时候长不长,B亮的时候长不长,一个位置长不长,长多少都是可以用当前时间和之前时间来计算的
1表示A亮时候长,2表示B亮时候长,3表示两种都长

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define MAXN 300010
#define GET (ch>='0'&&ch<='9')
#define Abs(x) (x>=0?x:-x)
using namespace std;
inline void in(int &x)
{
    char ch=getchar();x=0;
    while (!GET)    ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();
}
int Tim,n,m,top,tp;
int cnt[MAXN][4];
struct edge;
struct seg;
vector<edge*> now[MAXN][4];
struct edge
{
    seg *pre,*nxt;
    inline void solve();
    inline void merge();
}List[MAXN<<1];
struct seg
{
    int l,r,flag,h0,t0;
    edge *pre,*nxt;
    inline int calc()   {   return h0+cnt[Tim][flag]-cnt[t0][flag]; }
    inline bool checka()    {   return pre&&pre->pre->calc()>calc();   }
    inline bool checkb()    {   return nxt&&nxt->nxt->calc()>calc();   }
    inline void update()    {   flag=checka()|(checkb()<<1);  }
}*first,*last,list[MAXN<<1];
inline void edge::solve()
{
    int delta=abs(pre->calc()-nxt->calc()),flag=pre->flag^nxt->flag;
    if (delta&&flag&&cnt[Tim][flag]+delta<=300000)   now[cnt[Tim][flag]+delta][flag].push_back(this);
}
inline void edge::merge()
{
    if (!(pre&&nxt))    return;
    int h=pre->calc();
    if (nxt->calc()!=h)  return;
    seg* ret=pre;
    ret->l=pre->l;ret->r=nxt->r;ret->h0=h;ret->t0=Tim;
    ret->pre=pre->pre;ret->nxt=nxt->nxt;ret->update();
    if (ret->pre)    ret->pre->nxt=ret;
    if (ret->nxt)    ret->nxt->pre=ret;
    if (ret->pre)    ret->pre->solve();
    if (ret->nxt)    ret->nxt->solve();
    pre=NULL;nxt=NULL;
}
int main()
{
    in(n);in(m);int h;char ch=' ';
    for (int i=1;i<=n;i++)
    {
        in(h);
        if (last&&last->h0==h)   {   last->r=i;continue;  }
        ++top;list[top].l=i;list[top].r=i;list[top].h0=h;list[top].t0=0;
        if (last)
            ++tp,List[tp].pre=last,List[tp].nxt=&list[top],
            last->nxt=&List[tp],list[top].pre=&List[tp],last->update();
        else    first=&list[top];
        last=&list[top];
    }
    last->update();
    for (seg *i=first;i->nxt;i=i->nxt->nxt)    i->nxt->solve();
    while (ch!='A'&&ch!='B')    ch=getchar();
    for (Tim=1;Tim<=m;Tim++)
    {
        cnt[Tim][1]=cnt[Tim-1][1]+(ch=='A');cnt[Tim][2]=cnt[Tim-1][2]+(ch=='B');
        cnt[Tim][3]=cnt[Tim-1][3]+1;
        for (int f=1;f<=3;f++)
        {
            int it=now[cnt[Tim][f]][f].size();
            for (int i=0;i<it;i++)   now[cnt[Tim][f]][f][i]->merge();
        }
        if (Tim==m)
        {
            for (seg* i=first;i;i=i->nxt?i->nxt->nxt:NULL)
                for (int j=i->l;j<=i->r;++j)
                {
                    if (j>1) putchar(' ');
                    printf("%d",i->calc());
                }
            putchar('\n');
        }
        ch=getchar();
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值