[BZOJ3236]作业

作业

题目描述

image

输入格式

image

输出格式

image

样例

样例输入

3 4
1 2 2
1 2 1 3
1 2 1 1
1 3 1 3
2 3 2 3

样例输出

2 2
1 1
3 2
2 1

数据范围与提示

N=100000,M=1000000

真难受,打了两节半晚课,一开始连点思路都没有,颓题解发现全世界的题解都是"莫队+分块/树状数组"就结束了,一气之下颓了代码,我不是人,看了半天才研究明白代码(?),这也不是个多难的题啊,我更不是人了,结果发现颓的代码是个WA0的?一脸懵逼,我今天招惹谁了?mmp,我发现我最近每天晚上都要吐槽一大堆,最近运势不太对,讲题吧,明天该考试了,期待rp++

我怕我写个莫队+树状数组然后贴个代码会rp--,所以说一说吧,顺便复习一下树状数组(我发现我都忘光了),后面的pa大哥现在在说这是道水题,我???又是一脸懵逼,不扯了

其实这道题说是莫队其实挺明显的,查询区间还不用修改,莫队很优秀啊,不过关于那个大于等于a,小于等于b,其实我没想到怎么处理,后来颓完代码,觉得,树状数组真是个优秀的办法,单点修改,区间查询,莫队+树状数组优秀啊,我们来想想树状数组要维护些什么,偷偷告诉你,要两个树状数组哦显然,问题既然是两个,那就维护那两个问题呗,一个维护区间中出现过多少个不同的数,一个维护区间中一共多少个数,这样的话,我们用莫队进行++--的操作,然后对于每个询问中的[a,b]进行区间查询,优秀的不的了,然后树状数组一波搞,然后就可以A了,不过关于出现了多少个不同的数值可不能随随便便搞,他只能是当你区间中只有一个这个数,你把它搞掉了,或者没有这个数,你搞进来了一个,才可以修改这个答案,一共有多少个数,每次移动区间都修改就对了,emm,大概真的就是个莫队的模板+树状数组的模板,还是我太弱了,不过这题分块也可以,有兴趣的自己试一试,说不定线段树也没毛病呢

 1 //数值的个数就是只算一遍
 2 //数的个数就是重复的也算
 3 #include<cmath>
 4 #include<cstdio>
 5 #include<iostream>
 6 #include<algorithm>
 7 #define maxn 100010
 8 #define maxm 1000100
 9 using namespace std;
10 struct node{
11     int l,r,a,b,bh,sz,s;
12 }q[maxm];
13 int n,m,kc;
14 int a[maxn],ss[maxn],SZ[maxm],S[maxm],cs[maxm];
15 int lowbit(int x)
16 {
17     return x&(-x);
18 }
19 bool cmp(const node &a,const node &b)
20 {
21     return ss[a.l]==ss[b.l]?a.r<b.r:a.l<b.l;
22 }
23 bool cmpp(const node &a,const node &b)
24 {
25     return a.bh<b.bh;
26 }
27 void add(int x,int c)
28 {
29     for(int i=x;i<=n;i+=lowbit(i))  S[i]+=c;
30 }
31 void addd(int x,int c)
32 {
33     for(int i=x;i<=n;i+=lowbit(i))  SZ[i]+=c;
34 }
35 int sum(int x)
36 {
37     int c=0;
38     for(int i=x;i;i-=lowbit(i))  c+=S[i];
39     return c;
40 }
41 int summ(int x)
42 {
43     int c=0;
44     for(int i=x;i;i-=lowbit(i))  c+=SZ[i];
45     return c;
46 }
47 void upd(int x,int c)
48 {
49     if(c==1&&++cs[a[x]]==1)  addd(a[x],c);
50     if(c==-1&&--cs[a[x]]==0)  addd(a[x],c);
51     add(a[x],c);
52 }
53 int main()
54 {
55     scanf("%d%d",&n,&m);  kc=sqrt(n);
56     for(int i=1;i<=n;++i)  {scanf("%d",&a[i]);  ss[i]=i/kc+1;}
57     for(int i=1;i<=m;++i)
58     {
59         scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].a,&q[i].b);
60         q[i].bh=i;
61     }
62     sort(q+1,q+m+1,cmp);
63     int z=1,y=0;
64     for(int i=1;i<=m;++i)
65     {
66         while(z<q[i].l)  upd(z++,-1);
67         while(z>q[i].l)  upd(--z,1);
68         while(y<q[i].r)  upd(++y,1);
69         while(y>q[i].r)  upd(y--,-1);
70         q[i].s=sum(q[i].b)-sum(q[i].a-1);
71         q[i].sz=summ(q[i].b)-summ(q[i].a-1);
72     }
73     sort(q+1,q+m+1,cmpp);
74     for(int i=1;i<=m;++i)  printf("%d %d
",q[i].s,q[i].sz);
75     return 0;
76 }
跑了27s的代码
原文地址:https://www.cnblogs.com/hzjuruo/p/11240890.html