01匹配

題目鏈接: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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章