bzoj 4939: [Ynoi2016]掉进兔子洞
Posted zjxxcn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 4939: [Ynoi2016]掉进兔子洞相关的知识,希望对你有一定的参考价值。
有 m 个询问,每次询问三个区间,把三个区间中同时出现的数一个一个删掉,问最后三个区间剩下的数的个数和,询问独立。
注意这里删掉指的是一个一个删,不是把等于这个值的数直接删完,
比如三个区间是 [1,2,2,3,3,3,3] , [1,2,2,3,3,3,3] 与 [1,1,2,3,3],就一起扔掉了 1 个 1,1 个 2,2 个 3。
Input
第一行两个数表示 n , m。
第二行 n个数表示 a[i]。
之后 m 行,每行 6 个数 l1 , r1 , l2, r2 , l3 , r3 表示这三个区间。
Output
对于每个询问,输出一个数表示答案。
Sample Input
5 2
1 2 2 3 3
1 2 2 3 3 4
1 5 1 5 1 5
1 2 2 3 3
1 2 2 3 3 4
1 5 1 5 1 5
Sample Output
3
0
0
HINT
n , m <= 100000 , 1 <= a[i] <= 1000000000
首先,很显然这题是要用莫队来处理的。我们先把输入的数字另外排一下序,然后记录一下pi表示每一个数字对应在排好序的数列里面是排第几个。询问的时候要把一个询问拆成3个询问,然后再并起来。然后在莫队的时候记录cnti表示当前数字i出现的次数,再开一个bitset,假设当前需要加入bitset的数字是x,我们就令bitset中的第px+cntx位为1,然后++cntx。这样就会使得把三个bitset并起来之后,恰好剩下的就是在三个区间都出现了的数字,也就是需要删除的数字,我们就只需要看并起来之后还剩多少个1就行了
还有一个问题,就是我们必须要对每一个询问(拆之前)都要开一个bitset来存答案,但这会开不下。所以我们就要平衡一下空间复杂度和时间复杂度,把询问分为几块来处理
所以其实程序还可以更快一些,那就是在给所有的块排好序之后再分块。但这样写起来有点麻烦,所以我就懒得卡了(很有道理,但是我没写)
ps: 这里我发现了bitset还是调用他的函数比较快。
比如now[x]=1 我改成了now.flip(x) 就快了很多。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int const N=100000+10; 4 int const B=350; 5 int const T=25000; 6 struct query 7 int l,r,id; 8 bool operator < (const query &rhs)const 9 if(l/B!=rhs.l/B) return l/B<rhs.l/B; 10 return r<rhs.r; 11 12 q[N]; 13 int a[N],b[N],n,m,sum[N],ans[N],tot,cnt[N],p[N]; 14 bitset<N> s[T+1],now; 15 void solve() 16 for(int i=1;i<=tot/3;i++) s[i].set(); 17 for(int i=1;i<=100000;i++) cnt[i]=0; 18 now.reset(); 19 int l=1,r=0; 20 for(int i=1;i<=tot;i++) 21 while (l>q[i].l) 22 --l; now.flip(p[a[l]]+cnt[a[l]]); cnt[a[l]]++; 23 24 while (r<q[i].r) 25 ++r; now.flip(p[a[r]]+cnt[a[r]]); cnt[a[r]]++; 26 27 while (l<q[i].l) 28 cnt[a[l]]--; now.flip(p[a[l]]+cnt[a[l]]);l++; 29 30 while (r>q[i].r) 31 cnt[a[r]]--; now.flip(p[a[r]]+cnt[a[r]]);r--; 32 33 s[q[i].id]&=now; 34 35 for(int i=1;i<=tot/3;i++) 36 printf("%d\n",sum[i]-s[i].count()*3); 37 38 39 int main() 40 scanf("%d%d",&n,&m); 41 for(int i=1;i<=n;i++) 42 scanf("%d",&a[i]),b[i]=a[i]; 43 sort(b+1,b+n+1); 44 int k=unique(b+1,b+n+1)-b-1; 45 for(int i=1;i<=n;i++) 46 a[i]=lower_bound(b+1,b+k+1,a[i])-b; 47 memcpy(b,a,sizeof(a)); 48 sort(b+1,b+n+1); 49 for(int i=n;i>=1;i--) 50 p[b[i]]=i; 51 int num=(m+T-1)/T; 52 for(int i=1;i<=num;i++) 53 tot=0; 54 for(int j=(i-1)*T+1;j<=min(i*T,m);j++) 55 int x1,y1,x2,y2,x3,y3; 56 scanf("%d%d%d%d%d%d",&x1,&y1,&x2,&y2,&x3,&y3); 57 q[++tot].l=x1; q[tot].r=y1; q[tot].id=j-(i-1)*T; 58 q[++tot].l=x2; q[tot].r=y2; q[tot].id=j-(i-1)*T; 59 q[++tot].l=x3; q[tot].r=y3; q[tot].id=j-(i-1)*T; 60 sum[j-(i-1)*T]=y1-x1+y2-x2+y3-x3+3; 61 62 sort(q+1,q+tot+1); 63 solve(); 64 65 return 0; 66
以上是关于bzoj 4939: [Ynoi2016]掉进兔子洞的主要内容,如果未能解决你的问题,请参考以下文章