[Hall定理 + 线段树] LibreOJ#6062. 「2017 山东一轮集训 Day2」Pair

来源:互联网 发布:云和大数据的关系 编辑:程序博客网 时间:2024/06/01 09:52

可以先对 B 排序,然后 A 中的每个数能匹配的 B 中的元素都是一个后缀的形式。
对于一个 A 元素的集合是否与 B 有完美匹配呢? 可以考虑Hall定理,随便选一个B中的集合S:
由于图的特殊性,N(S)=N(S) ,也就是说只要所有后缀都满足 N(S)|S|,则任意集合都满足。
这样就很简单了,只要满足对于所有i, N(i)i 即可。
枚举所有可能子段,用线段树维护 N(i)i 的最小值,就好了。

#include<cstdio>#include<algorithm>using namespace std;const int maxn=200005;int n,m,H,ans,a[maxn],b[maxn],L[maxn];struct node{    int _min,tag; node* ch[2];      node(int x=0){_min=x;tag=0;ch[0]=ch[1]=0;}    void Plus(int x){ _min+=x; tag+=x; }    void pushdown(){ if(tag) ch[0]->Plus(tag), ch[1]->Plus(tag), tag=0; }    void maintain(){ _min=min(ch[0]->_min,ch[1]->_min); }} *root, base[maxn*2], *p_top=base;typedef node* P_node;void Updata(P_node p,int L,int R,int qL,int qR,int val){    if(R<qL||qR<L||qL>qR) return;    if(qL<=L&&R<=qR){ p->Plus(val); return; }    int mid=(L+R)>>1; p->pushdown();    Updata(p->ch[0],L,mid,qL,qR,val); Updata(p->ch[1],mid+1,R,qL,qR,val);    p->maintain();}P_node newnode(){ *p_top=node(2e9); return p_top++; }P_node Build(int L,int R){    P_node p=newnode();    if(L==R){ p->_min=-L; return p; }    int mid=(L+R)>>1;    p->ch[0]=Build(L,mid); p->ch[1]=Build(mid+1,R);    p->maintain(); return p;}int Find(int x){    int L=1,R=m,res=m+1;    while(L<=R){ int mid=(L+R)>>1; if(x<=b[mid]) R=mid-1, res=mid; else L=mid+1; }    return res;}int main(){    freopen("loj6062.in","r",stdin);    freopen("loj6062.out","w",stdout);    scanf("%d%d%d",&n,&m,&H);    for(int i=1;i<=m;i++) scanf("%d",&b[i]);    sort(b+1,b+1+m);     for(int i=1;i<=n;i++) scanf("%d",&a[i]),L[i]=Find(H-a[i]);     if(m>n) return puts("0"),0;    root=Build(1,m);    for(int i=1;i<=m;i++) Updata(root,1,m,L[i],m,1);    for(int i=m;i<=n;i++,Updata(root,1,m,L[i],m,1),Updata(root,1,m,L[i-m],m,-1))     if(root->_min>=0) ans++;    printf("%d\n",ans);    return 0;}
阅读全文
0 0