zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    STM32:SPI&w25qxx的配置与代码
    STM32:USART的原理与配置
    C的抽象数据类型:二叉树
    DSP:TMS320C66x 系列SPI NOR自启动
    C的抽象数据类型:链表、队列
    STM32:GPIO口的使用
    STM32:时钟树
    STM32:预备知识
    makefile:简单小结
    ubuntu:tar、apt、vim、gcc的配置和简单使用
  • 原文地址:https://www.cnblogs.com/zhangxianlong/p/11568734.html
Copyright © 2011-2022 走看看