P4396

[AHOI2013]作业

一个比较深必的做法就是直接莫队加树状数组统计。

一开始 T 了后面两个点。

经过我的不懈卡常,开 O2 的情况下过掉了。

具体方法包括但不限于循环展开、奇偶排序。。。

这个复杂度是 $O(n\sqrt{m}\log n)$ 的,显然是错的。

正确的解法应该是把树状数组换为值域分块,这样就能支持 $O(1)$ 单点修改/查询,$O(\sqrt{n})$ 单次区间查询了。

最后总的复杂度是 $O(m\sqrt{n}+n\sqrt{m})$。这个复杂度是对的。

但我都卡常卡过了还写啥呢/ts。

实际上好像也挺好写的。

中间写的时候犯了个深必的错误,把 pos[q[i].l] 写成了 q[i].l 结果还过了前面几个点。。。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
namespace Ehnaev{
inline ll read() {
ll ret=0,f=1;char ch=getchar();
while(ch<48||ch>57) {if(ch==45) f=-f;ch=getchar();}
while(ch>=48&&ch<=57) {ret=(ret<<3)+(ret<<1)+ch-48;ch=getchar();}
return ret*f;
}
inline void write(ll x) {
static char buf[22];static ll len=-1;
if(x>=0) {do{buf[++len]=x%10+48;x/=10;}while(x);}
else {putchar(45);do{buf[++len]=-(x%10)+48;x/=10;}while(x);}
while(len>=0) putchar(buf[len--]);
}
}using Ehnaev::read;using Ehnaev::write;
inline void writes(ll x) {write(x);putchar(32);}
inline void writeln(ll x) {write(x);putchar(10);}

const ll N=2e6;

ll n,m,nn,cntblo;
ll a[N+5],pos[N+5],c[N+5],c_[N+5];

struct Block{ll l,r;}blo[N+5];

struct Qry{ll l,r,a,b,ans1,ans2,id;}q[N+5];

inline bool Cmp1(Qry x,Qry y) {return x.l<y.l;}
inline bool Cmp2(Qry x,Qry y) {return x.r<y.r;}
inline bool Cmp3(Qry x,Qry y) {return x.r>y.r;}
inline bool Cmp4(Qry x,Qry y) {return x.id<y.id;}

inline void Add(ll x,ll y) {for(;x<=N;x+=x&-x) c[x]+=y;}
inline void Add_(ll x,ll y) {for(;x<=N;x+=x&-x) c_[x]+=y;}
inline ll Ask(ll x) {ll r=0;for(;x;x-=x&-x) r+=c[x];return r;}
inline ll Ask_(ll x) {ll r=0;for(;x;x-=x&-x) r+=c_[x];return r;}

inline void Modify(ll from,ll to,bool op) {
if(from==to) return;
ll type=(from<to)^op;
if(type) {
if(from<to) {
for(ll i=from+1;i<=to;i++) {
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],1);
Add(a[i],1);
i++;if(i>to) break;
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],1);
Add(a[i],1);
i++;if(i>to) break;
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],1);
Add(a[i],1);
i++;if(i>to) break;
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],1);
Add(a[i],1);
i++;if(i>to) break;
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],1);
Add(a[i],1);
i++;if(i>to) break;
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],1);
Add(a[i],1);
}
}
else {
for(ll i=from-1;i>=to;i--) {
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],1);
Add(a[i],1);
i--;if(i<to) break;
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],1);
Add(a[i],1);
i--;if(i<to) break;
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],1);
Add(a[i],1);
i--;if(i<to) break;
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],1);
Add(a[i],1);
i--;if(i<to) break;
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],1);
Add(a[i],1);
i--;if(i<to) break;
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],1);
Add(a[i],1);
}
}
}
else {
if(from<to) {
for(ll i=from;i<to;i++) {
Add(a[i],-1);
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],-1);
i++;if(i>=to) break;
Add(a[i],-1);
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],-1);
i++;if(i>=to) break;
Add(a[i],-1);
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],-1);
i++;if(i>=to) break;
Add(a[i],-1);
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],-1);
i++;if(i>=to) break;
Add(a[i],-1);
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],-1);
i++;if(i>=to) break;
Add(a[i],-1);
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],-1);
}
}
else {
for(ll i=from;i>to;i--) {
Add(a[i],-1);
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],-1);
i--;if(i<=to) break;
Add(a[i],-1);
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],-1);
i--;if(i<=to) break;
Add(a[i],-1);
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],-1);
i--;if(i<=to) break;
Add(a[i],-1);
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],-1);
i--;if(i<=to) break;
Add(a[i],-1);
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],-1);
i--;if(i<=to) break;
Add(a[i],-1);
if(Ask(a[i])-Ask(a[i]-1)==0) Add_(a[i],-1);
}
}
}
}

int main() {

n=read();m=read();
nn=max(1ll,(ll)n/(ll)sqrt(m));
for(ll i=1;i<=n;i++) {a[i]=read();}
cntblo=1;
for(ll i=1;i<=n;i+=nn,cntblo++) {
blo[cntblo].l=i;blo[cntblo].r=i+nn-1;
if(blo[cntblo].r>n) blo[cntblo].r=n;
for(ll j=blo[cntblo].l;j<=blo[cntblo].r;j++) pos[j]=cntblo;
}
cntblo--;



for(ll i=1;i<=m;i++) {
q[i].l=read();q[i].r=read();q[i].a=read();q[i].b=read();q[i].id=i;
}
sort(q+1,q+m+1,Cmp1);

ll lst=1;
for(ll i=1,j=1;j<=cntblo;j++) {
while(pos[q[i].l]==j) i++;
if(j&1) sort(q+lst,q+i,Cmp2);
else sort(q+lst,q+i,Cmp3);
lst=i;
}

ll lit=1,rit=1;Add(a[1],1);Add_(a[1],1);
for(ll i=1;i<=m;i++) {
Modify(rit,q[i].r,0);rit=q[i].r;
Modify(lit,q[i].l,1);lit=q[i].l;
q[i].ans1=Ask(q[i].b)-Ask(q[i].a-1);
q[i].ans2=Ask_(q[i].b)-Ask_(q[i].a-1);
}

sort(q+1,q+m+1,Cmp4);

for(ll i=1;i<=m;i++) {
writes(q[i].ans1);writeln(q[i].ans2);
}

return 0;
}