[bzoj5042][ST表]LWD的分科岛

版权声明:蒟蒻的blog... https://blog.csdn.net/Rose_max/article/details/78071780

Description

大家都知道在文理分科的时候总是让人纠结的,纠结的当然不只是自己。比如 YSY 就去读了文科, LWD 知道了很
气。于是他就去卡了 BZOJ 测评机, 晚上他做了一个谜一样的梦,自己在一座全是 YSY 的分科岛。这里有 YSY
草, YSY 花, YSY 糖……每个 YSY 都有一个美( Ti)丽( Zhong)值。当然没有小于零的体重啦!LWD 于是不
惜重金卖肉想买下这座岛,可是分科岛的岛主,是一位忠实的区间问题爱好者。他想把小岛传给一个谜一样的爱好
者,所以岛主给了 LWD 一个终极挑战——选出一片区域中最美丽的 YSY。可是岛主的审美观不像 YYR那么专一,
他有时喜欢现代美——最轻的,有时喜欢唐代美——最重的。这让被欢喜冲昏了头脑(血液集中在下半身)的 LWD
十分苦恼。他要在规定时间内完成挑战赢得买岛的权利,于是只有求助 DalaoYYR,可是 YYR 要准备课件啊。只
有比 YYR 弱很多的你能够帮他了。挑战内容如下岛主将把 N 个 YSY 摆成一个条形,并给出所有 YSY 的美丽值。
挑出多少个就要看岛主心情了,他觉得 LWD 是条汉子就会给出很多很多的 YSY 满足他。岛主将给出 Q 个考验,
询问内容是在给定区间内求出最美丽的 YSY。你已经了解规则了,开始你的表演吧!

Input

第一行为一个整数 N,表示岛主摆出了 N 个 YSY。
接下来一行 N 个整数,表示每个 YSY 的美丽值(单位:kg),因为 YSY 整体很美所以 YSY
不会超过 1019kg。
接下来一行一个整数 Q,表示岛主有 Q 个考验。Q<=1500000
接下来 Q 行,每行三个整数 opt, l, r 。 opt 等于 1 时表示岛主那时喜欢现代美,等于 2
时代表岛主那时喜欢唐代美。询问最美计划在区间[l, r]中进行
100%的数据 N<= 3000000, 美丽值不会超过 1019, Q<= 150000
数据量巨大,请优化读入

Output

每一行对于每个考验输出结果,以回车符结束。

Sample Input

5 5
1 2 3 4 5
1 1 2
2 1 3
1 2 5
2 4 5
2 1 5

Sample Output

1
3
2
5
5

正经题解前说的话

写了这篇题解没想到帮了这么多被毒瘤题卡住的人。。
不过我还真想到了除了On的rmq外的东西。就是可持久化01tire
对于每个点反着建01tire,即高位的深度较低
然后像主席树那样合并起来搞可持久化数据结构。。
这样可以弄出来一个空间小于st表时间小于线段树的东西
至于我是怎么想到的??这个魅力值<=1019很可疑啊
但是我发现我又被卡空间了。。各路神犇可以指导一下吗

//这是MLE的代码
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
struct node
{
    int lc,rc,c0,c1;//lc 0  rc 1 
}tr[30000005];int tot;
int tmp[15];
void getlen(int x)
{
    int p=11;
    if(x==0){for(int i=1;i<=11;i++)tmp[i]=0;return ;}
    while(x)
    {
        tmp[p--]=x%2;
        x/=2;
    }
    for(int i=1;i<=p;i++)tmp[i]=0;
}
int rt[3100000];
void add()
{
    int x=++tot;
    for(int i=1;i<=11;i++)
    {
        if(tmp[i]==0){tr[x].c0++;tr[x].lc=++tot;x=tr[x].lc;}
        else {tr[x].c1++;tr[x].rc=++tot;x=tr[x].rc;}
    }
}
void merge(int &x,int y)
{
    if(x==0){x=y;return ;}
    if(y==0)return ;
    tr[x].c0+=tr[y].c0;
    tr[x].c1+=tr[y].c1;
    merge(tr[x].lc,tr[y].lc);
    merge(tr[x].rc,tr[y].rc);
}
int bin[20],ans;
int solmax(int x,int y)
{
    ans=0;
    int px=x,py=y;
    for(int i=11;i>=1;i--)
    {
        int c=tr[px].c1-tr[py].c1;
        if(c>0)
        {
            ans+=bin[i];
            px=tr[px].rc;py=tr[py].rc;
        }
        else if(tr[px].c0-tr[py].c0>0){px=tr[px].lc;py=tr[py].lc;}
        else break;
    }
    return ans;
}
int solmin(int x,int y)
{
    ans=0;
    int px=x,py=y;
    for(int i=11;i>=1;i--)
    {
        int c=tr[px].c0-tr[py].c0;
        if(c>0){px=tr[px].lc;py=tr[py].lc;}
        else if(tr[px].c1-tr[py].c1>0){ans+=bin[i];px=tr[px].rc;py=tr[py].rc;}
        else break;
    }
    return ans;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    bin[1]=1;for(int i=2;i<=15;i++)bin[i]=bin[i-1]*2;
    tot=0;
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        getlen(x);
        rt[i]=tot+1;add();merge(rt[i],rt[i-1]);
    }
    while(m--)
    {
        int op,l,r;
        scanf("%d%d%d",&op,&l,&r);
        if(op==1)printf("%d\n",solmin(rt[r],rt[l-1]));
        else printf("%d\n",solmax(rt[r],rt[l-1]));
    }
    return 0;
}

题解

首先,说点东西。。每个询问长度才1000左右?????
所以这可以投机一点st表。。但是估计是卡着时间过去的
还有。。不能定两个数组,两个数组都会炸。。还得一个数组拆开来用。。
所以说切了这题还是觉得很无奈。。
两个数组维护最大最小值然后Nlogn求吧。bzoj上大佬D说可以线性RMQ然而不会,就卡下数据吧。
正解好像是On的RMQ 可以参照一下OZY大佬的blog


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
int mn[11][3000001],s[3000001],Log[3000001];
int ans[1500001];
int x[1500001],y[1500001],k[1500001];
int n,m;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void premn()
{
    //mn[i][j]=min(mn[i-1][j],mn[i-1][j+1<<i])
    Log[0]=-1;
    for(int i=1;i<=n;i++)Log[i]=Log[i/2]+1;
    for(int i=1;(1<<i)<=n && i<=10;i++)
        for(int j=1;j+(1<<i)-1<=n && j<=n;j++)
        {
            mn[i][j]=min(mn[i-1][j],mn[i-1][j+(1<<(i-1))]);
        }
}
int maxnum;
void premx()
{
    for(int i=1;i<=n;i++)mn[0][i]=s[i];
    for(int i=1;(1<<i)<=maxnum && i<=10;i++)
        for(int j=1;j+(1<<i)-1<=maxnum && j<=maxnum;j++)
        {
            mn[i][j]=max(mn[i-1][j],mn[i-1][j+(1<<(i-1))]);
        }
}
int main()
{
//  freopen("naive.in","r",stdin);
//  freopen("naive.out","w",stdout);
    n=read();m=read();
    for(int i=1;i<=n;i++){mn[0][i]=s[i]=read();}

    premn();int tmp=0;maxnum=0;
    for(int i=1;i<=m;i++)
    {
        int op=read(),xx=read(),yy=read();
        if(op==1)
        {
            int kk=Log[yy-xx+1];
            ans[i]=min(mn[kk][xx],mn[kk][yy-(1<<kk)+1]);
        }
        else
        {
            tmp++;
            x[tmp]=xx;y[tmp]=yy;k[tmp]=i;
            maxnum=max(maxnum,yy);
        }
    }
    premx();
    for(int i=1;i<=tmp;i++)
    {
        int kk=Log[y[i]-x[i]+1];
        ans[k[i]]=max(mn[kk][x[i]],mn[kk][y[i]-(1<<kk)+1]);
    }
    for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
    return 0;
}
阅读更多

没有更多推荐了,返回首页