zoukankan      html  css  js  c++  java
  • loj#6062. 「2017 山东一轮集训 Day2」Pair

    首先这题对于 $a[l,l+m-1]$ 能够成功匹配,当且仅当去连边,然后能形成完美匹配。

    但是边数可能到 $m^2$ 的级别,所以跑不了 dinic,但我们只需要判断是否有。

    于是,考虑 hall 定理,即对于二分图一部的子集 $S$,每个点在另一部连得边的并集 $S'$,有 $|S| le |S'|$,则该二分图有完美匹配。

    考虑线段树维护前缀 $could_i-i$。

    $$[1,r],rle could_r$$

    $$[l,r],l-1le could_{l-1},rle could_{r}$$

    $$r-(l-1)le could_{r}-could_{l-1}$$

    $$could_i-ige0$$

    对于一部的点集动态,就不能先 $build$ 了。

    实际上 $b$ 升序/顺序没有影响。处理麻烦或简单而已。

    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <map>
    
    #define ll long long
    
    using namespace std;
    int rd() {
    	int f=1,sum=0; char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    ll lrd() {
    	ll f=1,sum=0; char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    #define ls (cur<<1)
    #define rs (ls|1)
    
    const int N=(int)(1.5e5+5);
    int mi[N<<2],tag[N<<2];
    int n,m,h,a[N],b[N];
    
    void push_up(int cur) {
    	mi[cur]=min(mi[ls],mi[rs]);
    }
    
    void push_down(int cur) {
    	if(!tag[cur]) return ;
    	tag[ls]+=tag[cur]; tag[rs]+=tag[cur];
    	mi[ls]+=tag[cur]; mi[rs]+=tag[cur];
    	tag[cur]=0;
    }
    
    void build(int cur,int l,int r) {
    	mi[cur]=0x3f3f3f3f;
    	if(l==r) return mi[cur]=-l,void();
    	int mid=(l+r)>>1;
    	build(ls,l,mid); build(rs,mid+1,r);
    	push_up(cur);
    }
    
    void update(int cur,int l,int r,int cl,int cr,int v) {
    	if(cl<=l&&r<=cr) {
    		tag[cur]+=v; mi[cur]+=v; return ;
    	}
    	push_down(cur);
    	int mid=(l+r)>>1;
    	if(cl<=mid) update(ls,l,mid,cl,cr,v);
    	if(cr>mid) update(rs,mid+1,r,cl,cr,v);
    	push_up(cur);
    }
    
    int main() {
    	n=rd(); m=rd(); h=rd();
    	for(int i=1;i<=m;i++) b[i]=rd();
    	for(int i=1;i<=n;i++) a[i]=rd();
    	sort(b+1,b+1+m);
    	build(1,1,m);
    	int ans=0; // a[i]+b[i]>=h a[i]-h>=b[i]
    	for(int i=1;i<=m;i++) {
    		int p=lower_bound(b+1,b+1+m,h-a[i])-b;
    		if(p<=m) update(1,1,m,p,m,1);
    	}
    	ans+=mi[1]>=0;
    	for(int i=m+1;i<=n;i++) {
    		int p=lower_bound(b+1,b+1+m,h-a[i-m])-b;
    		if(p<=m) update(1,1,m,p,m,-1);
    		p=lower_bound(b+1,b+1+m,h-a[i])-b;
    		if(p<=m) update(1,1,m,p,m,1);
    		ans+=mi[1]>=0;
    	}
    	printf("%d",ans); return 0;
    }
    

      

  • 相关阅读:
    ASP.NET 2.0
    PHP
    SQL 查询逻辑处理顺序
    LEETCODE
    网络学习课程资源
    概率论
    集合论
    图论
    《组合数学》
    离散数学
  • 原文地址:https://www.cnblogs.com/xugangfan/p/15210578.html
Copyright © 2011-2022 走看看