題目鏈接:01匹配
如果對於一個區間來說,我們肯定是貪心對0匹配之前最近的1.
然後我們可以發現兩個區間是可以簡單合併的。
直接線段樹即可。
AC代碼:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=3e5+10;
int n,q,x;
struct node{int n0,n1,res;}t[N<<2],c;
#define mid (l+r>>1)
inline node merge(node a,node b){
int tmp=min(a.n1,b.n0);
c.res=a.res+b.res+tmp;
c.n0=a.n0+b.n0-tmp;
c.n1=a.n1+b.n1-tmp;
return c;
}
void build(int p,int l,int r){
if(l==r){scanf("%d",&x); if(x==1) t[p].n1=1; else t[p].n0=1; return ;}
build(p<<1,l,mid),build(p<<1|1,mid+1,r);
t[p]=merge(t[p<<1],t[p<<1|1]);
}
node ask(int p,int l,int r,int ql,int qr){
if(l==ql&&r==qr) return t[p];
if(qr<=mid) return ask(p<<1,l,mid,ql,qr);
else if(ql>mid) return ask(p<<1|1,mid+1,r,ql,qr);
else return merge(ask(p<<1,l,mid,ql,mid),ask(p<<1|1,mid+1,r,mid+1,qr));
}
signed main(){
cin>>n; build(1,1,n); cin>>q;
for(int i=1,l,r;i<=q;i++) scanf("%d %d",&l,&r),printf("%d\n",ask(1,1,n,l,r).res);
return 0;
}