题目大意:
给
n
n
n 个数,有
m
m
m 个询问,每次询问给出区间
[
l
,
r
]
[l,r]
[l,r],回答区间
[
l
,
r
]
[l,r]
[l,r] 中和为 0 的最大长度。
数据范围:
1
<
=
n
,
m
<
=
50000
1 <= n,m <= 50000
1<=n,m<=50000
思路: 区间和为 0 ,那么显然 利用前缀和判相等是最好的方法。先将前缀和离散化,然后利用 50000条双端队列,维护每一个前缀和出现的位置。小的放前面,大的放后面。
当 add 或者 del 位置 x 时,就只需要改变 a[x] 的那一条队列即可。
可知 需要维护的东西就是每一种长度出现的次数,以及长度的最大值。
利用权值线段树可以很轻易的维护这个东西。每一次更新都是
O
(
l
o
g
n
)
O(logn)
O(logn),查询$O(1)
(当要求区间和为
k
k
k 时,就只是在
a
[
x
]
a[x]
a[x] ,
a
[
x
]
+
k
a[x] + k
a[x]+k,
a
[
x
]
−
k
a[x] - k
a[x]−k 这三条队列选更新)
!!! 值得注意的一点就是莫队千万不要自以为,比如这个题在
d
e
l
del
del函数中,所使用的队列长度并不一定是 >= 2的
Code:
#include<bits/stdc++.h>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define ls i << 1
#define rs (i << 1) + 1
#define fi first
#define se second
#define ptch putchar
#define CLR(a) while(!(a).empty()) a.pop()
using namespace std;
inline LL read() {
LL s = 0,w = 1;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-')
w = -1;
ch = getchar();
}
while(isdigit(ch))
s = s * 10 + ch - '0',ch = getchar();
return s * w;
}
inline void write(LL x) {
if(x < 0)
putchar('-'), x = -x;
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
const int maxn = 2e5 + 10;
int Ls[maxn],a[maxn],n,m;
int ans[maxn],belong[maxn];
struct xx {
int l,r,id;
} Q[maxn];
int cmp(xx a, xx b) {
return (belong[a.l] ^ belong[b.l]) ?
belong[a.l] < belong[b.l] :
((belong[a.l] & 1) ? a.r < b.r : a.r > b.r);
}
deque<int>deq[maxn];
int maxx[maxn << 2],ok[maxn];
void update(int l,int r,int pos,int i,int val){
if(l == r){
ok[l] += val;
maxx[i] = (ok[l] <= 0 ? 0 : l);
return ;
}
int mid = (l + r) >> 1;
if(pos <= mid) update(l,mid,pos,ls,val);
if(pos > mid) update(mid + 1,r,pos,rs,val);
maxx[i] = max(maxx[ls],maxx[rs]);
}
void del(int x,bool flag) { ///0在首,1在尾
int fro = deq[a[x]].front();
int bac = deq[a[x]].back();
update(1,n,bac - fro,1,-1);
if(!flag) deq[a[x]].pop_front();
else deq[a[x]].pop_back();
if(deq[a[x]].empty()) return ;
int tmp = (flag == 0 ? deq[a[x]].front() : deq[a[x]].back());
update(1,n,flag == 0 ? bac - tmp : tmp - fro,1,1);
}
void add(int x,bool flag) {
if(deq[a[x]].empty()) {
deq[a[x]].push_front(x);
return ;
}
int fro = deq[a[x]].front();
int bac = deq[a[x]].back();
if(!flag) deq[a[x]].push_front(x);
else deq[a[x]].push_back(x);
update(1,n,bac - fro,1,-1);
update(1,n,flag == 0 ? bac - x : x - fro,1,1);
}
int main() {
//#ifndef ONLINE_JUDGE
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
//#endif
n = read(),m = read();
int block = sqrt(n);
rep(i,1,n + 1) {
a[i] = read();
a[i] += a[i - 1];
Ls[i] = a[i];
belong[i] = (i - 1) / block + 1;
}
++ n; Ls[n] = 0;
sort(Ls + 1,Ls + 1 + n);
int en = unique(Ls + 1,Ls + 1 + n) - Ls - 1;
rep(i,0,n) a[i] = lower_bound(Ls + 1,Ls + 1 + en,a[i]) - Ls;
rep(i,1,m + 1) {
Q[i].l = read();
Q[i].r = read();
Q[i].id = i;
}
sort(Q + 1,Q + m + 1,cmp);
int L = 1,R = 0;
deq[a[0]].push_front(0);
for(int i = 1; i <= m; ++ i) {
while(L > Q[i].l) -- L,add(L - 1,0);
while(R < Q[i].r) add(++ R,1);
while(L < Q[i].l) del(L - 1,0),L ++;
while(R > Q[i].r) del(R --,1);
ans[Q[i].id] = maxx[1];
}
for(int i = 1; i <= m; ++ i)
write(ans[i]), ptch('\n');
return 0;
}