JZOJ5623. 【NOI2018模拟4.2】program

题目

这里写图片描述

题目大意

给出一个操作序列,询问给出一个区间,
求这个区间操作所产生的答案。

题解

假设先对原操作序列求一次答案,
那么询问的某个区间的答案就一定是连续的一段。
有了这个想法,这题就很简单了。

首先先在操作序列的最前端添加一定数量的”>”保证指针不会从左边出去,
维护0-9的前缀和,已经每一个位置第一次被左边的位置的时刻 fi f i 以及第一次被右边的位置到达的时刻 gi g i
用链表来处理删除一个字符。
维护 gi g i 的时候要注意这个字符可能已经被删去。

有了这些信息,对于一次查询l,r,
那么进入这个区间的时刻就是 fi f i
离开这个区间的时刻就是min( gl,fr+1 g l , f r + 1 )
用前缀和减一下就是答案了。

code

#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <vector>
#define ll long long
#define N 200003
#define M 103
#define db double
#define P putchar
#define G getchar
#define inf 998244353
#define pi 3.1415926535897932384626433832795
using namespace std;
char ch;
void read(int &n)
{
    n=0;
    ch=G();
    while((ch<'0' || ch>'9') && ch!='-')ch=G();
    ll w=1;
    if(ch=='-')w=-1,ch=G();
    while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
    n*=w;
}

int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}

char s[N];
int pre[N],nxt[N],d[N*10],n,m,f[N],g[N];
int x,y,tot,p1,p2,id,lst;
int S[10][N*5],z[N],top;

void del(int x)
{
    nxt[pre[x]]=nxt[x];
    pre[nxt[x]]=pre[x];
}

int main()
{
    freopen("program2.in","r",stdin);
    freopen("program.out","w",stdout);

    read(n);read(m);

    for(ch=G();(ch<'0' || ch>'9') && ch!='<' && ch!='>';ch=G());

    nxt[0]=1;
    for(int i=1;i<=n;i++)
    {
        s[i]=ch;ch=G();
        pre[i]=i-1;nxt[i]=i+1;
        if(s[i]=='<')
        {
            tot++;
            s[n+tot]='>';
            pre[nxt[n+tot]=nxt[0]]=n+tot;
            nxt[0]=n+tot;
        }
    }
    nxt[n]=n+tot+1;id=1;

    for(x=1,y=0;x && x!=n+tot+1;lst=x,x=p2)
    {           
        p1=pre[x];p2=nxt[x];

        if(y)
        {
            swap(p1,p2);
            while((z[top]>x || x>n) && top)g[z[top--]]=id;
        }else
        {
            if(!g[x] && x<=n)z[++top]=x;
            if(x<=n && !f[x])f[x]=id;
        }

        if(s[x]=='<' || s[x]=='>')
        {
            if(s[lst]=='<' || s[lst]=='>')del(lst);
            if(s[x]=='>')y=0;else y=1;
            p1=pre[x];p2=nxt[x];
            if(y)swap(p1,p2);
        }
        else
        {
            id++;
            for(int i=0;i<=9;i++)
                S[i][id]=S[i][id-1];
            S[s[x]-48][id]++;
            if(s[x]==48)del(x);
            s[x]--;
        }

    }

    for(int i=1;i<=m;i++)
    {
        read(p1);read(p2);
        x=f[p1];y=min(g[p1]?g[p1]:id,f[p2+1]?:id);
        for(int j=0;j<=9;j++)
            write(S[j][y]-S[j][x]),P(' ');
        P('\n');
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值