六 一 欢乐给给赛 T3题解

六 一 欢乐给给赛 T3题解

题目传送门
这道题其实很简单,题如其名,不知道各路dalao为何装弱。
第一种解法:
对于每个查询进行贪心
复杂度: O ( ( Q + 1 ) n ) = O ( n 2 )
实际得分:30
代码什么的就不粘了,大家肯定都会写。
第二种解法:
我们考虑到每个数都是正整数,说明以 a i 为lsq序列的第一个元素的话,结尾的元素 a j 的下标 j 是固定的,也就是可以产生类似树(森林)的结构,我们就可以在树上倍增了。
正解就是队列建树+倍增求解
复杂度 O ( n + Q l o g 2 n )
代码非常短

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
inline void read(int &x)
{
    int s=0,w=1;
    char c=getchar();
    while(!isdigit(c)){if(c=='-')w=-1;c=getchar();}
    while(isdigit(c)){s=(s<<3)+(s<<1)+c-'0',c=getchar();}
    x=s*w;
}
inline void write(int x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
const int MAXN=500010;
int fa[MAXN][20],deep[MAXN],x[MAXN],n,K,Q[MAXN],front=1,rear=0,sum[MAXN],T,bin[20];
int main()
{
    read(n),read(K);
    bin[0]=1;
    for(register int i=1;i<=19;i++)bin[i]=bin[i-1]<<1;
    for(register int i=1;i<=n;i++)read(x[i]);
    for(register int i=1;i<=n;i++)
    {
        sum[i]=sum[i-1]+x[i];
        while(front<=rear&&sum[i]-sum[Q[front]-1]>K)
        fa[Q[front++]][0]=i;
        Q[++rear]=i;
    }
    while(front<=rear)
    fa[front++][0]=n+1;
    for(register int j=1;j<=19;j++)
    for(register int i=1;i<=n;i++)
    fa[i][j]=fa[fa[i][j-1]][j-1];
    read(T);
    while(T--)
    {
        int L,R;
        read(L),read(R);
        int step=0;
        for(register int i=19;~i;i--)
            if(fa[L][i]&&fa[L][i]<=R&&L<R)step+=bin[i],L=fa[L][i];
        if(L<=R)step++;
        write(step),putchar(10);
    }
}

猜你喜欢

转载自blog.csdn.net/assass_cannotin/article/details/80544935
今日推荐