题目链接:https://codeforces.ml/contest/1562/problem/D2
思路:可以发现结果只和区间和的奇偶有关。区间和为0时答案为零,区间和为奇数时,需要找到[ l , r ]之间的某个数pos,使得去掉pos后,前面的和等于后面的和,两区间抵消。记sum为前缀和,则有sum[ pos - 1] - sum[ l - 1 ] = sum [ r ] - sum [ l ],整理得sum[ r ] + sum[ l - 1 ] = sum[ i ] + sum[ i - 1 ],而对于每个区间[ l , r ],左侧为定值,只需要预处理时将sum[ i ] + sum[ i - 1 ]加入i桶中,查询时查询第一个大于等于l的下标即为pos。可以加入2*N作为偏移量,使得下标非负。区间和为偶数时,去掉最后一个数或第一个数,即可转化成奇数情况。
ac代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5+5;
int t,n,q;
char ch[N];
int sum[N*10];
int a[N];
vector<int>v[N*4];
int main(){
ios::sync_with_stdio (false);
cin >> t;
while(t--){
for(int i = N*2-n*2;i < n*2+N*2;i++)v[i].clear();
cin >> n >> q;
for(int i = 1;i <= n;i++)cin >> ch[i];
for(int i = 1;i <= n;i++){
if(((i&1)&&(ch[i]=='+'))||((i&1)==0&&ch[i]=='-'))
a[i] = 1;
else a[i] = -1;
}
for(int i = 1;i <= n;i++)sum[i] = sum[i - 1] + a[i];
for(int i = 1;i <= n;i++)v[sum[i]+sum[i-1]+2*N].push_back(i);
while(q--){
int l,r;
cin >> l >> r;
int ans = sum[r] - sum[l - 1];
if(ans == 0)cout << 0 << endl;
else{
if(ans&1){
cout << 1 << endl;
}
else {
cout << 2 << endl << r << " ";
r--;
}
ans = sum[r] + sum[l - 1];
cout << v[ans+2*N][lower_bound(v[ans+2*N].begin(),v[ans+2*N].end(),l)-v[ans+2*N].begin()]<<endl;
}
}
}
return 0;
}