BZOJ3693:圆桌会议(Hall定理)

来源:互联网 发布:听四大名著的软件 编辑:程序博客网 时间:2024/05/16 11:34

传送门

题解:
按照题意,先把所有的人放在左边,所有的桌子。,如果有完备匹配就可以,否则就不可以。

显然直接匈牙利是会超时的。考虑二分图完备匹配的充要条件是满足Hall定理。那么问题转化为:对于任意人的子集X,连向的桌子个数|X|

先考虑链的情况:
此时的人的子集如果没有包含某个条件的完整的ai,那么此可以扩展至包含这个条件的所有ai(因为ai的连边都相同),而对于任意个数的条件,如果他们连向的区间不相交且不满足Hall定理,那么这个条件的子集也不满足Hall定理。假设把这个条件集合分为若干个相交的区间,那么其中一定有一个不满足Hall定理。

那么问题可以转化为对于任意桌子的区间[Li,Ri],所有他们包含的条件的ai和小于等于区间长度。

这个随便用个数据结构维护一下即可。

考虑环的情况:
先把链复制一遍,假设现在有不满足的区间,那么分为两种情况:
1.所有ai的和大于m,这个直接特判掉。
2.一部分ai的和大于包含他们的区间长度。(显然这个区间不是整个m,不然不会满足情况1)。
此时这个区间一定是首区间一段(可以为0)+尾区间一段(可以为0)的形式,证明和链的情况类似。此时把这条链倍长后一定可以判定出来。

那么这道题就可以愉快的O(nlogn)解决了。

#include<bits/stdc++.h>using namespace std;inline int rd(){    char ch=getchar();int i=0,f=1;    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}    while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}    return i*f;} const int Maxn=4e5+50;int T,n,m,lsh[Maxn],cnt,tot,mx[Maxn<<2],tag[Maxn<<2];struct data{    int l,r,c;    data(){}    data(int l,int r,int c):l(l),r(r),c(c){}}a[Maxn];inline bool cmpr(const data &a,const data &b){return a.r<b.r||(a.r==b.r&&a.l<b.l);}inline void add(int k,int v){mx[k]+=v;tag[k]+=v;}inline void pd(int k){    if(!tag[k])return;    add(k<<1,tag[k]),add(k<<1|1,tag[k]);    tag[k]=0;}inline void upt(int k){mx[k]=max(mx[k<<1],mx[k<<1|1]);}inline void modify(int k,int l,int r,int L,int R,int v){    if(L<=l&&r<=R){add(k,v);return;}    pd(k);int mid=(l+r)>>1;    if(R<=mid)modify(k<<1,l,mid,L,R,v);    else if(L>mid)modify(k<<1|1,mid+1,r,L,R,v);    else modify(k<<1,l,mid,L,R,v),modify(k<<1|1,mid+1,r,L,R,v);    upt(k);}inline int querymx(int k,int l,int r,int L,int R){    if(L<=l&&r<=R)return mx[k];    pd(k);int mid=(l+r)>>1;    if(R<=mid)return querymx(k<<1,l,mid,L,R);    else if(L>mid)return querymx(k<<1|1,mid+1,r,L,R);    else return max(querymx(k<<1,l,mid,L,R),querymx(k<<1|1,mid+1,r,L,R));}inline void solve(){    n=rd(),m=rd();long long sum=0;    for(int i=1;i<=n;i++)++cnt,a[cnt].l=rd(),a[cnt].r=rd(),a[cnt].c=rd(),sum+=a[cnt].c;    if(sum>m){puts("No");return;}     for(int i=1;i<=n;i++)if(a[i].l>a[i].r)a[i].r+=m;    for(int i=1;i<=n;i++)if(a[i].r<m)a[++cnt]=data(a[i].l+m,a[i].r+m,a[i].c);    for(int i=1;i<=cnt;i++)a[i].l++,a[i].r++;    for(int i=1;i<=cnt;i++){lsh[++tot]=a[i].l,lsh[++tot]=a[i].r;}    sort(lsh+1,lsh+tot+1);tot=unique(lsh+1,lsh+tot+1)-lsh-1;    sort(a+1,a+cnt+1,cmpr);int tl=0;    for(int i=1;i<=cnt;i++){        int r=lower_bound(lsh+1,lsh+tot+1,a[i].r)-lsh,l=lower_bound(lsh+1,lsh+tot+1,a[i].l)-lsh;        while(tl<r){++tl;modify(1,1,tot,tl,tl,lsh[tl]-1);}        modify(1,1,tot,1,l,a[i].c);        if(querymx(1,1,tot,max(1ll,lower_bound(lsh+1,lsh+tot+1,a[i].l-m+1)-lsh),r)>lsh[r]){puts("No");return;}    }    puts("Yes");}int main(){    T=rd();    while(T--){        memset(tag,0,sizeof(tag));        memset(mx,0,sizeof(mx));        tot=0;cnt=0;        solve();    }}