[BZOJ2724][Violet 6]蒲公英(分块)

16 篇文章 0 订阅

题目描述

传送门

题解

预处理一坨。
块外暴力。
块内sort(关键字先权值再位置),然后二分找。

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
using namespace std;

const int max_n=4e4+5;
const int max_t=2e2+5;

int n,m,cnt,t1,t2,l,r;
int a[max_n],b[max_n],c[max_n],mp[max_n],num[max_n];
int last[max_t];
struct hp{
    int val,num;
}aa[max_n];
struct hq{
    int l,r;
}k[max_n];
int val[max_n],number[max_n];
int ans,ansk;
int key[max_t][max_t],sum[max_t][max_t],s[max_n];

inline int cmp1(int x,int y){
    return b[x]<b[y];
} 

inline int cmp(hp a,hp b){
    return a.val<b.val||(a.val==b.val&&a.num<b.num);
}

inline void add(int i,int tot){
    s[a[i]]+=tot;
    if (s[a[i]]>ans){
        ans=s[a[i]];
        ansk=mp[a[i]];
    }
    else if (s[a[i]]==ans&&ansk>mp[a[i]])
      ansk=mp[a[i]];
}

inline void Query(int l,int r){
    int lrange,rrange;
    memset(s,0,sizeof(s));
    ans=ansk=0;

    if (num[l]==num[r]){
        for (int i=l;i<=r;++i)
          add(i,1);
        printf("%d\n",ansk);
        return;
    }

    if (l!=last[num[l]-1]+1)
        lrange=num[l]+1;
    else lrange=num[l];

    if (r!=last[num[r]])
        rrange=num[r]-1;
    else rrange=num[r];
    ans=sum[lrange][rrange];
    ansk=mp[key[lrange][rrange]];

    if (l!=last[num[l]-1]+1)
      for (int i=l;i<=last[num[l]];++i)
        if (!s[a[i]]){
            add(i,1);
            int loc1=k[a[i]].l;
            int loc2=k[a[i]].r;
            int loc3=lower_bound(number+loc1,number+loc2+1,lrange)-number;
            if (loc3>loc2) continue;
            int loc4=upper_bound(number+loc1,number+loc2+1,rrange)-number-1;
            if (loc3>loc4) continue;
            int tot=loc4-loc3+1;
            add(i,tot);
        }
        else
          add(i,1);
    if (r!=last[num[r]])
      for (int i=last[num[r]-1]+1;i<=r;++i)
        if (!s[a[i]]){
            add(i,1);
            int loc1=k[a[i]].l;
            int loc2=k[a[i]].r;
            int loc3=lower_bound(number+loc1,number+loc2+1,lrange)-number;
            if (loc3>loc2) continue;
            int loc4=upper_bound(number+loc1,number+loc2+1,rrange)-number-1;
            if (loc3>loc4) continue;
            int tot=loc4-loc3+1;
            add(i,tot);
        }
        else
          add(i,1);
    printf("%d\n",ansk);
}

int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;++i){
        scanf("%d",&b[i]);
        c[i]=i;
    }
    sort(c+1,c+n+1,cmp1);
    for (int i=1;i<=n;++i)
      if (b[c[i]]!=b[c[i-1]])
        a[c[i]]=++cnt;
      else a[c[i]]=cnt;
    for (int i=1;i<=n;++i)
      mp[a[i]]=b[i];

    int t1=(int)sqrt(n);
    if (n%t1==0)
      t2=n/t1;
    else
      t2=n/t1+1;
    for (int i=1;i<=n;++i)
      if (i%t1==0)
        num[i]=i/t1;
      else
        num[i]=i/t1+1;
    for (int i=1;i<=t2;++i)
      last[i]=min(i*t1,n);  

    for (int i=1;i<=n;++i){
        aa[i].val=a[i];
        aa[i].num=num[i];
    }
    sort(aa+1,aa+n+1,cmp);
    for (int i=1;i<=n;++i){
        val[i]=aa[i].val;
        number[i]=aa[i].num;
    }

    k[1].l=1;
    for (int i=2;i<=n;++i)
      if (val[i]!=val[i-1]){
        k[val[i]].l=i;
        k[val[i-1]].r=i-1;
      }
    k[cnt].r=n;

    int head=0,tail=0;
    ans=ansk=0;
    while (head<=t2){
        head++;
        tail=head;
        memset(s,0,sizeof(s));
        ans=ansk=0;
        for (int i=last[head-1]+1;i<=last[head];++i){
            ++s[a[i]];
            if (s[a[i]]>ans){
                ans=s[a[i]];
                ansk=a[i];
            }
            else if (s[a[i]]==ans&&ansk>a[i])
              ansk=a[i];
        }
        key[head][tail]=ansk;
        sum[head][tail]=ans;

        while (tail<=t2){
            tail++;
            for (int i=last[tail-1]+1;i<=last[tail];++i){
                ++s[a[i]];
                if (s[a[i]]>ans){
                    ans=s[a[i]];
                    ansk=a[i];
                }
                else if (s[a[i]]==ans&&ansk>a[i])
                  ansk=a[i];
            }
            key[head][tail]=ansk;
            sum[head][tail]=ans;
        }
    }

    ans=ansk=0;
    for (int i=1;i<=m;++i){
        scanf("%d%d",&l,&r);
        l=(l+ansk-1)%n+1;
        r=(r+ansk-1)%n+1;
        if (l>r) swap(l,r);
        Query(l,r);
    }
}

总结

代码跑的慢。姿势太蠢?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值