ssoj2427: 学数数(RMQ)

来源:互联网 发布:wampserver mac版 编辑:程序博客网 时间:2024/05/16 15:38

题意:一个数组有n个数,能够分成n(n+1)/2个连续子数组。记录这些子数组的最大数。有q个询问,求满足询问的数字有多少个。


思路:o^2肯定超。离散化。对于当前的数,找到他左右两边第一个大于它的数,左边的距离(x),右边的距离(y),f[当前数]+=x+y+x*y。RMQ记录区间最大值。

各种细节写挂了。。。(1)要开long long,与ll相关的也要ll。(2)因为离散了,所以对询问的数要判断一下是否是离散前的数。。。


贴代码:

#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <algorithm>#define ll long longusing namespace std;const int maxn=1000006;int n,q,k,a[maxn],b[maxn],dp[100005][31],p[100005][31],mxb=0,mx=0;ll f[maxn],ans,cnt=0,sum[maxn];inline int get(){    char c;while(!isdigit(c=getchar()));    int v=c-48;while(isdigit(c=getchar()))v=v*10+c-48;    return v;}inline void RMQ(){    for(int i=1;i<=n;++i)dp[i][0]=a[i],p[i][0]=i;    int k=log2(n*1.0);      for(int j=1;j<=k;++j)        for(int i=1;i+(1<<j)-1<=n;++i){if(dp[i+(1<<(j-1))][j-1]>dp[i][j-1])dp[i][j]=dp[i+(1<<(j-1))][j-1],p[i][j]=p[i+(1<<(j-1))][j-1];else dp[i][j]=dp[i][j-1],p[i][j]=p[i][j-1];}}inline int getpos(int l,int r){    int k=log2((r-l+1)*1.0);    if(dp[l][k]>dp[r-(1<<k)+1][k])return p[l][k];    else return p[r-(1<<k)+1][k];}inline void Find(int l,int r){    if(l>=r)return;    int t=getpos(l,r);    int x=t-l,y=r-t;    f[a[t]]+=(ll)x+(ll)y+(ll)x*y;    Find(l,t-1);    Find(t+1,r);}int main(){    n=get();q=get();    for(int i=1;i<=n;++i)b[i]=a[i]=get(),mxb=max(mxb,b[i]);    sort(b+1,b+1+n);    int tmp=unique(b+1,b+1+n)-b-1;    for(int i=1;i<=n;++i)a[i]=lower_bound(b+1,b+1+tmp,a[i])-b,++f[a[i]],mx=max(a[i],mx);    RMQ();    Find(1,n);sum[0]=f[0]=0;    for(int i=1;i<=mx;++i)sum[i]+=sum[i-1]+f[i-1],cnt+=f[i];    while(q--){    char op;    op=getchar();    while(!(op=='>'||op=='='||op=='<'))op=getchar();int x=get();    int t=lower_bound(b+1,b+1+tmp,x)-b;    if(op=='>'){    if(t>mx)ans=0;    else{if(x!=b[t])ans=cnt-sum[t];else ans=cnt-sum[t]-f[t];}}if(op=='='){    if(x==b[t])ans=f[t];    else ans=0;}if(op=='<'){    if(t>mx)ans=cnt;    else ans=sum[t];}printf("%lld\n",ans);}return 0;}












0 0
原创粉丝点击