题解 a
真·就我切不掉签到题
其实口头切了,但做法太恶心了所以写不出来
发现每个位置最多进行一次操作 1
所以 check 一个区间可以贪心,看会不会有减成负数或弄不成偶数的地方
没有 0 的话就只需要考虑有没有弄不成偶数的地方
一个区间合法的条件是区间内有偶数个奇数
容易想到扫描线+线段树历史和,需要支持区间 0/1 取反和区间历史和
然而……
- 对于线段树区间 0/1 取反和区间历史和:
其实并不需要真的写历史和,只需要开两棵线段树,每棵每个位置的权值为 \([这个位置应该在这棵线段树上]*val(i)\) 即可
也可以推广到轮换之类
那么其实直接扫描线,在两棵线段树上区间加就好了
然后考虑有 0 怎么做
正经做法是继续扫描线,那么找到前面一个 0 和前面最近的一个 包含了奇数个 1 的区间的左端点的 0
那么可以用这两个 0 确定能产生贡献的区间,根据前缀和奇偶性选线段树做区间加即可
接下来是赛时的鬼畜做法(但应该是对的):
考虑在线处理询问
将极长无 0 段和极长全 0 段称为一个块
那么每个块内的贡献可以线段树历史和预处理
然后考虑跨块的子区间
称一个包含奇数个 1 的块为坏块
那么相邻坏块会将块的序列分为若干个大块
令在每个块中选一个包含偶数个 1 的后缀方案数为 \(f_i\),选一个合法前缀方案数为 \(g_i\)
那么一个大块的贡献是
\[\sum\limits_if_i\sum\limits_{j>i}g_j
\]
可以预处理
然后考虑两个边角
合法区间为 总合法区间 - 左端点在 r 以右的(可以对每个块预处理乘积的后缀和)- \(\sum\limits_{i}^{r-1}f_i\sum\limits_{j>r}g_j\)
于是就可以做了,复杂度也是 \(O(n\log n)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 500010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans;
}
int n, q;
int a[N];
namespace force{
int b[N];
bool check(int l, int r) {
for (int i=l; i<=r; ++i) b[i]=a[i];
for (int i=l; i<=r; ++i) {
if (b[i]<0) return 0;
if (b[i]&1) {
if (i==r) return 0;
else --b[i], --b[i+1];
}
}
return 1;
}
void solve() {
for (int i=1,l,r; i<=q; ++i) {
l=read(); r=read();
int ans=0;
for (int j=l; j<=r; ++j)
for (int k=j; k<=r; ++k)
ans+=check(j, k);
printf("%d\n", ans);
}
}
}
namespace task1{
vector<int> able[N];
vector<pair<int, int>> que[N];
int ans[N], val[N], sum[N], b[N];
void solve() {
for (int i=1; i<=n; ++i) {
for (int j=i; j<=n; ++j) b[j]=a[j];
for (int j=i; j<=n; ++j) {
if (b[j]<0) break;
if (b[j]&1) --b[j], --b[j+1];
else able[i].pb(j);
}
}
for (int i=1,l,r; i<=q; ++i) {
l=read(); r=read();
que[l].pb({r, i});
}
for (int i=n; i; --i) {
for (auto& it:able[i]) ++val[it];
for (int j=i; j<=n; ++j) sum[j]=sum[j-1]+val[j];
for (auto& it:que[i]) ans[it.sec]=sum[it.fir];
}
for (int i=1; i<=q; ++i) printf("%d\n", ans[i]);
}
}
namespace task2{
bool val[N], rev[N];
int bel[N], ls[N], rs[N], len;
vector<pair<int, int>> que[N];
ll ans[N], his[N], his_b[N], sum[N], siz[N], rsiz[N], cnt[N], rcnt[N];
int tem=0;
void build(int id) {
for (int i=ls[id]; i<=rs[id]; ++i) {
his_b[id]+=his[i];
siz[id]+=val[i];
}
rsiz[id]=(rs[id]-ls[id]+1)-siz[id];
// ++tem;
// sum[id]=his_b[id]+siz[id]*cnt[id]+((rs[id]-ls[id]+1)-siz[id])*rcnt[id];
}
void upd(int l, int r, int dat) {
int sid=bel[l], eid=bel[r];
if (sid==eid) {
for (int i=l; i<=r; ++i) his[i]+=(val[i]^=dat);
if (l==ls[sid]) build(sid);
return ;
}
for (int i=l; bel[i]==sid; ++i) his[i]+=(val[i]^=dat);
for (int i=sid+1; i<=eid; ++i) {
rev[i]^=dat;
if (rev[i]) ++rcnt[i];
else ++cnt[i];
}
if (l==ls[sid]) build(sid);
}
ll query(int l, int r) {
ll ans=0;
int sid=bel[l], eid=bel[r];
if (sid==eid) {
for (int i=l; i<=r; ++i) {
ans+=his[i];
if (val[i]) ans+=cnt[sid];
else ans+=rcnt[sid];
}
return 1ll*(r-l+1)*(r-l+2)/2-ans;
}
for (int i=l; bel[i]==sid; ++i) {
ans+=his[i];
if (val[i]) ans+=cnt[sid];
else ans+=rcnt[sid];
}
for (int i=sid+1; i<eid; ++i) ans+=his_b[i]+siz[i]*cnt[i]+rsiz[i]*rcnt[i];
// for (int i=sid+1; i<eid; ++i) ans+=sum[i];
for (int i=r; bel[i]==eid; --i) {
ans+=his[i];
if (val[i]) ans+=cnt[eid];
else ans+=rcnt[eid];
}
return 1ll*(r-l+1)*(r-l+2)/2-ans;
}
// void upd(int l, int r, int dat) {
// for (int i=l; i<=r; ++i) his[i]+=(val[i]^=dat);
// }
// ll query(int l, int r) {
// ll ans=0;
// for (int i=l; i<=r; ++i) ans+=his[i];
// return 1ll*(r-l+1)*(r-l+2)/2-ans;
// }
void solve() {
len=sqrt(n);
memset(ls, 0x3f, sizeof(ls));
for (int i=1; i<=n; ++i) bel[i]=(i-1)/len+1;
for (int i=1; i<=n; ++i) ls[bel[i]]=min(ls[bel[i]], i), rs[bel[i]]=max(rs[bel[i]], i);
for (int i=1,l,r; i<=q; ++i) {
l=read(); r=read();
que[l].pb({r, i});
}
for (int i=n; i; --i) {
// cout<<"i: "<<i<<endl;
if (a[i]&1) upd(i, n, 1);
else upd(i, n, 0);
// cout<<"his: "; for (int j=1; j<=n; ++j) cout<<his[j]<<' '; cout<<endl;
for (auto it:que[i]) ans[it.sec]=query(i, it.fir);
}
for (int i=1; i<=q; ++i) printf("%lld\n", ans[i]);
// cerr<<"tem: "<<tem<<endl;
}
}
namespace task{
ll ans[N], sum[N];
vector<pair<int, int>> que[N];
struct segment{
int tl[N<<2], tr[N<<2];
ll k[N<<2], sum[N<<2], tag[N<<2];
#define tl(p) tl[p]
#define tr(p) tr[p]
#define pushup(p) k[p]=k[p<<1]+k[p<<1|1], sum[p]=sum[p<<1]+sum[p<<1|1]
void spread(int p) {
if (!tag[p]) return ;
sum[p<<1]+=k[p<<1]*tag[p]; tag[p<<1]+=tag[p];
sum[p<<1|1]+=k[p<<1|1]*tag[p]; tag[p<<1|1]+=tag[p];
tag[p]=0;
}
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r;
if (l==r) return ;
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
}
void enable(int p, int pos) {
if (tl(p)==tr(p)) {k[p]=1; return ;}
spread(p);
int mid=(tl(p)+tr(p))>>1;
if (pos<=mid) enable(p<<1, pos);
else enable(p<<1|1, pos);
pushup(p);
}
void upd(int p, int l, int r) {
if (l<=tl(p)&&r>=tr(p)) {sum[p]+=k[p]; ++tag[p]; return ;}
spread(p);
int mid=(tl(p)+tr(p))>>1;
if (l<=mid) upd(p<<1, l, r);
if (r>mid) upd(p<<1|1, l, r);
pushup(p);
}
ll query(int p, int l, int r) {
if (l<=tl(p)&&r>=tr(p)) return sum[p];
spread(p);
int mid=(tl(p)+tr(p))>>1; ll ans=0;
if (l<=mid) ans+=query(p<<1, l, r);
if (r>mid) ans+=query(p<<1|1, l, r);
return ans;
}
}seg[2];
void solve() {
for (int i=1; i<=n; ++i) sum[i]=sum[i-1]+a[i];
for (int i=1,l,r; i<=q; ++i) {
l=read(); r=read();
que[r].pb({l, i});
}
seg[0].build(1, 0, n); seg[1].build(1, 0, n);
seg[0].enable(1, 0);
int pos=0, lst=0;
for (int i=1,cnt=0; i<=n; ++i) {
// cout<<"i: "<<i<<' '<<lst<<endl;
if (a[i]&1) ++cnt;
seg[sum[i]&1].enable(1, i); //, cout<<"enable: "<<(sum[i]&1)<<' '<<i<<endl;
if (cnt&1) seg[sum[i]&1].upd(1, lst, i-1); //, cout<<1<<' '<<lst+1<<' '<<i-(a[i]&1)<<endl;
else seg[sum[i]&1].upd(1, pos, i-1); //, cout<<2<<endl;
if (!a[i]) {
if (cnt&1) pos=lst;
lst=i; cnt=0;
}
for (auto it:que[i]) {
// cout<<it.fir<<' '<<it.sec<<endl;
ans[it.sec]+=seg[0].query(1, it.fir-1, i)+seg[1].query(1, it.fir-1, i);
}
}
for (int i=1; i<=q; ++i) printf("%lld\n", ans[i]);
}
}
signed main()
{
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
n=read(); q=read();
bool no_zero=1;
for (int i=1; i<=n; ++i) if ((a[i]=read())==0) no_zero=0;
// force::solve();
// if (n<=5000) task1::solve();
// else task2::solve();
task::solve();
return 0;
}