Hall 定理

理论部分

原定理

对于一个二分图,两个条件等价:

  1. 存在一种方案,使得所有左部点都能顺着边匹配到一个右部点,且每个右部点只匹配一次。
  2. 左边任意取 \(k\) 个点,这些点能到达的右部点一定大于等于 \(k\) 个。

充分性:已经有 \(k\) 个右部点匹配了,只会多不会少。
必要性:如果只有一个左部点一定成立,否则删去一对匹配点,仍然满足条件。

扩展 1

对于一个二分图,两个条件等价:

  1. 存在一种方案,使得第 \(i\) 个左部点都能顺着边匹配到 \(h_i\) 个右部点,且每个右部点只匹配一次。
  2. 左边任意取 \(k\) 个点 \(\set{p_1,p_2,\cdots,p_k}\),这些点能到达的右部点一定大于等于 \(\sum_{i=1}^k h_{p_i}\) 个。

证明:将第 \(i\) 个左部点点拆分成 \(h_i\) 个单点,下同原定理。

扩展 2

对于一个二分图,两个条件等价:

  1. 存在一种方案,使得不超过 \(a\) 个左部点不能顺着边匹配到一个右部点,且每个右部点只匹配一次。
  2. 左边任意取 \(k\) 个点,这些点能到达的右部点一定大于等于 \(k-a\) 个。

证明:开 \(a\) 个虚右部点,和左边所有点连边,
则新图中原定理条件 1 等价于条件 1,则新图中原定理条件 2 等价于条件 2。

题目

P3488

由于对应鞋码不相交的两端区间可以合并,没有附加条件,所以我们只考虑相交情况。
直接对着 Hall 定理抄答案,设 \(i\) 号脚有 \(p_i\) 个人,
需要判断每一个子段 \(\sum_{i=l}^r p_i\le (\min\set{n,r+d}-l+1)\)
等价于 \(\sum_{i=l}^r p_i-(\min\set{n-d,r}-l+1)=\sum_{i=l}^r ({p_i-[i\le n-d]})\le d\)
等价于对于初始 \(p_i=-[i\le n-d]\) 的数组直接去修改,求最大子段和小于等于 \(d\)
一次修改操作,左面的不会有影响,右面的需要分讨。
我们需要找到右面第一个前缀和比当前这个地方小的,再往右都不会受影响。
于是我们可以开两个线段树,
一个记录前缀和,负责每次修改和线段树二分;
一个记录最大子段和,根据指令进行区间加和,全局求 \(\max\)

线段树二分是什么?
就是先用线段树性质去分区间,如果左边有就返回左边,否则右边有就返回右边,否则返回没有。

//线段树二分示例代码
//这里是查找区间第一个小于 base 的元素,k 数组存储的是区间 min。
int query(int i,int l,int r,int L,int R,int base){
    if(k[i]>base) return -1;
    if(l!=r) pushdown(i,l,r);
    if(l==L&&r==R){
        if(l==r) return l;
        int mid=(l+r)>>1;
        if(k[ls]<base) return query(i<<1,l,mid,l,mid,base);
        if(k[rs]<base) return query(i<<1|1,mid+1,r,mid+1,r,base);
    }
    if(R<=mid) return query(i<<1,l,mid,L,R,base);
    if(L>mid) return query(i<<1|1,mid+1,r,L,R,base);
    int tmp=query(i<<1,l,mid,L,mid,base);
    return (tmp==-1)?query(i<<1|1,mid+1,r,mid+1,R,base):tmp;
}
posted @ 2026-01-06 17:25  2025ing  阅读(13)  评论(0)    收藏  举报