您的位置:首页 > 其它

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

2016-03-31 23:57 435 查看

题目描述

传送门

题解

预处理一坨。

块外暴力。

块内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);
}
}


总结

代码跑的慢。姿势太蠢?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: