hiho1996 : 01匹配 线段树

hiho1996 : 01匹配 线段树

https://hihocoder.com/problemset/problem/1996

题意

你有一个n个点的图。

第i个点有权值ai,每个点的权值只可能是1或者0。

点i和点j之间有连边,当且仅当以下两个条件满足:

i < j

ai = 1 且 aj = 0

有q次询问,每次询问给出l和r,请回答:如果我们只保留标号在[l,r]之间的点,只保留两个端点编号都在[l,r]之间的那些边,那么这个图的最大匹配是多少,请输出最大匹配数。

思路

题目描述的怪玄乎,仔细观察一下这个要求的东西是有结合律的,也就是维护答案加上区间多余的0和1的个数,就可以合并两个相邻区间。显然可以搞个线段树来做。
ps.既然搞了线段树,那实际上这个东西也是区间修改的。

代码

#include<bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define PB push_back
#define MP make_pair
#define MEM(a,b) memset(a,b,sizeof(a))
typedef long long ll;
const ll mod = 1e9+7;
const int maxn =3e6+10;

int sum[maxn][2],sit[maxn];

inline int lson(int x){return x*2;}

inline int rson(int x){return x*2+1;}

void push_up(int rt){
    sit[rt]=sit[lson(rt)]+sit[rson(rt)];
    sum[rt][0]=sum[lson(rt)][0]+sum[rson(rt)][0];
    sum[rt][1]=sum[lson(rt)][1]+sum[rson(rt)][1];
    if(sum[lson(rt)][1]>0&&sum[rson(rt)][0]>0){
        sit[rt]+=min(sum[lson(rt)][1],sum[rson(rt)][0]);
        sum[rt][1]-=min(sum[lson(rt)][1],sum[rson(rt)][0]);
        sum[rt][0]-=min(sum[lson(rt)][1],sum[rson(rt)][0]);
    }
}

void build(int rt,int L,int R,vector<int> &a){
    if(L==R){
        sit[rt]=0;
        sum[rt][a[L]]++;
        return;
    }
    int mid=(L+R)/2;
    build(lson(rt),L,mid,a);
    build(rson(rt),mid+1,R,a);
    push_up(rt);
}

pair<int,pair<int,int>> query(int rt,const int l,const int r,int L,int R){
    if(L>=l&&R<=r) return {sit[rt],{sum[rt][0],sum[rt][1]}};
    if(l>R||r<L) return {0,{0,0}};
    int mid=(L+R)/2;
    auto ll=query(lson(rt),l,r,L,mid);
    auto rr=query(rson(rt),l,r,mid+1,R);
    if(ll.X==-1) return rr;
    else if(rr.X==-1) return ll;
    else{
        pair<int,pair<int,int>> ret;
        ret.X=ll.X+rr.X;
        ret.Y.X=ll.Y.X+rr.Y.X;
        ret.Y.Y=ll.Y.Y+rr.Y.Y;
        int mi=min(ll.Y.Y,rr.Y.X);
        ret.Y.X-=mi;
        ret.Y.Y-=mi;
        ret.X+=mi;
        return ret;
    }
}

int main(){
    int n,m,l,r;
    cin>>n;
    vector<int> a(n+1,0);
    for(int i=1;i<=n;i++) cin>>a[i];
    build(1,1,n,a);
    cin>>m;
    while(m--){
        cin>>l>>r;
        cout<<query(1,l,r,1,n).X<<endl;
    }
    return 0;
}
posted @ 2019-09-22 19:10 zhangxianlong 阅读(...) 评论(...) 编辑 收藏