解题:AHOI 2013 作业

本文深入探讨了莫队算法的原理与应用,通过具体题目解析了如何利用莫队算法进行信息维护和分块查询,提供了详细的代码实现,并分析了算法的时间复杂度为O(m*sqrt(n)+n*sqrt(m))。

题面

emmm......我把莫队扔到了杂题里,因为感觉局限挺大的=。=

这题是莫队维护信息+分块查询答案,都是两者的基本操作,复杂度$O(m$ $sqrt(n)+n$ $sqrt(m))$

所以为啥要写这水题的题解来着

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int N=100005,Sq=320;
 7 struct a
 8 {
 9     long long ans,num;
10     int l,r,xx,yy,v,id; 
11 }mo[N];
12 int b[N],blo[N],cnt[N],exi[Sq],bkt[Sq],pts[Sq][2];
13 int n,m,t1,t2,t3,t4,lp,rp,sqr,srt,xnt,maxx;
14 bool cmp(a x,a y)
15 {
16     return x.v==y.v?x.r<y.r:x.v<y.v;
17 }
18 bool com(a x,a y)
19 {
20     return x.id<y.id;
21 }
22 void change(int val,int typ)
23 {
24     if(typ)
25     {
26         bkt[blo[val]]++;
27         exi[blo[val]]+=(++cnt[val]==1);
28     }
29     else
30     {
31         bkt[blo[val]]--;
32         exi[blo[val]]-=(!(--cnt[val]));
33     }
34 }
35 int query1(int x,int y)
36 {
37     int ret=0;
38     if(blo[x]!=blo[y])
39     {
40         for(int i=x;i<=pts[blo[x]][1];i++) ret+=cnt[i];
41         for(int i=pts[blo[y]][0];i<=y;i++) ret+=cnt[i];
42         for(int i=blo[x]+1;i<=blo[y]-1;i++) ret+=bkt[i];
43     }
44     else for(int i=x;i<=y;i++) ret+=cnt[i];
45     return ret;
46 }
47 int query2(int x,int y)
48 {
49     int ret=0;
50     if(blo[x]!=blo[y])
51     {
52         for(int i=x;i<=pts[blo[x]][1];i++) ret+=(cnt[i]>0);
53         for(int i=pts[blo[y]][0];i<=y;i++) ret+=(cnt[i]>0);
54         for(int i=blo[x]+1;i<=blo[y]-1;i++) ret+=exi[i];
55     }
56     else for(int i=x;i<=y;i++) ret+=(cnt[i]>0);
57     return ret;
58 }
59 int main ()
60 {
61     scanf("%d%d",&n,&m),sqr=sqrt(n);
62     for(int i=1;i<=n;i++) 
63         scanf("%d",&b[i]),maxx=max(maxx,b[i]);
64     for(int i=1;i<=m;i++)
65     {
66         scanf("%d%d%d%d",&t1,&t2,&t3,&t4);
67         mo[i].v=(t1-1)/sqr+1,mo[i].id=i,maxx=max(maxx,t4);
68         mo[i].l=t1,mo[i].r=t2,mo[i].xx=t3,mo[i].yy=t4; 
69     }
70     pts[xnt=1][0]=1,srt=sqrt(maxx);
71     for(int i=1;i<=n;i++)
72     {
73         blo[i]=(i-1)/srt+1;
74         if(i%srt==0)
75         {
76             pts[xnt++][1]=i;
77             pts[xnt][0]=i+1;
78         }
79     }
80     pts[xnt][1]=maxx,lp=1;
81     sort(mo+1,mo+1+m,cmp);
82     for(int i=1;i<=m;i++)
83     {
84         while(lp<mo[i].l) change(b[lp++],0);
85         while(lp>mo[i].l) change(b[--lp],1);
86         while(rp<mo[i].r) change(b[++rp],1);
87         while(rp>mo[i].r) change(b[rp--],0);
88         mo[i].ans=query1(mo[i].xx,mo[i].yy);
89         mo[i].num=query2(mo[i].xx,mo[i].yy);
90     }
91     sort(mo+1,mo+1+m,com);
92     for(int i=1;i<=m;i++)
93         printf("%lld %lld\n",mo[i].ans,mo[i].num);
94     return 0;
95 }
View Code

 

转载于:https://www.cnblogs.com/ydnhaha/p/9963950.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值