bzoj3693圆桌会议(二分图匹配hall定理+线段树)

3693:圆桌会议

时间限制: 5000 ms
内存限制: 262144 KB

题目描述

有n组人要一起开一个圆桌会议(编号为0~ n 1 ),会议的圆桌上有 m 个位置(编号为0~ m -1)。每个组有 a i 个人,他们需要被安排在( l i ( l i + 1 ) ( l i + 2 ) ,…, r i )的座位范围内。每个座位只能安排一个人就坐,并且每个人都需要被安排一个座位。现在你需要判断是否存在满足条件的座位安排。

输入

输入包含不超过10组数据。

第一行有一个数字 T ,表示数据组数。

接下来有 T 组数据,每组数据第一行包含两个数 n m ,表示有多少组的人与圆桌的位置数。

每组数据接下来包含 n 行,每行包含3个数 l i r i a i

输出

对于每组数据,输出” Y e s ”或” N o ”,表示是否存在符合条件的安排。

输入样例

2
2 4
0 1 2
1 2 2
2 3
2 0 2
1 1 1

输出样例

No
Yes

提示

T 10 ,其中有不超过3组的数据范围为 n 10 5 m 10 9









解:

其实这道题笔者也不会,可以去看hzwer的博客
注意几个问题,如果两个区间覆盖这个数列,且两个区间的个数加起来比总位置多,这种情况是判不了的,因为我们运用上面的方法只能判断覆盖不满圆桌的情况。因此,我们要特判人数大于位置数的情况。
还有就是为什么hall定理要求的是子集而hzwer验证的区间?
这里写图片描述
假如两个区间有交集,我们子集和区间是等价的。如果没有交集,我们会验证1-2和4-6,这样的话1-6就没有意义了,当然为了统一,我们还是象征性地验证了一下。
code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int T,n,cnt,m,tot;
int disc[400005];
struct que{int l,r,v;}q[200005];
struct seg{int l,r,mx,tag;}t[1200005];
inline bool operator<(que a,que b)
{
    return a.r<b.r;
}
void pushup(int k)
{
    t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx);
}
void pushdown(int k)
{
    if(t[k].l==t[k].r||!t[k].tag)return;
    int tag=t[k].tag;t[k].tag=0;
    t[k<<1].tag+=tag;t[k<<1].mx+=tag;
    t[k<<1|1].tag+=tag;t[k<<1|1].mx+=tag;
}
void build(int k,int l,int r)
{
    t[k].l=l;t[k].r=r;t[k].tag=0;
    if(l==r){t[k].mx=disc[l]-1;return;}
    int mid=(l+r)>>1;
    build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    pushup(k);
}
int find(int x)
{
    int l=1,r=tot;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(disc[mid]==x)return mid;
        else if(disc[mid]<x)l=mid+1;
        else r=mid-1;
    }
}
void update(int k,int x,int y,int val)
{
    pushdown(k);
    int l=t[k].l,r=t[k].r;
    if(l==x&&y==r)
    {
        t[k].tag+=val;t[k].mx+=val;
        return;
    }
    int mid=(l+r)>>1;
    if(y<=mid)update(k<<1,x,y,val);
    else if(x>mid)update(k<<1|1,x,y,val);
    else 
    {
        update(k<<1,x,mid,val);
        update(k<<1|1,mid+1,y,val);
    }
    pushup(k);
}
int query(int k,int x,int y)
{
    pushdown(k);
    int l=t[k].l,r=t[k].r;
    if(l==x&&y==r)
        return t[k].mx;
    int mid=(l+r)>>1;
    if(y<=mid)return query(k<<1,x,y);
    else if(x>mid)return query(k<<1|1,x,y);
    else return max(query(k<<1,x,mid),query(k<<1|1,mid+1,y));
}
int main()
{
    //freopen("conference.in","r",stdin);
    //freopen("conference.out","w",stdout);
    T=read();
    while(T--)
    {
        bool flag=0;tot=0;
        n=read();m=read();
        ll sum=0;
        for(int i=1;i<=n;i++)
        {
            q[i].l=read(),q[i].r=read(),q[i].v=read();
            q[i].l++;q[i].r++;sum+=q[i].v;
        }
        if(sum>m)
        {
            printf("No\n");
            continue;
        }
        cnt=n;
        for(int i=1;i<=n;i++)
            if(q[i].r<q[i].l)q[i].r+=m;
            else 
            {
                q[++cnt]=q[i];
                q[cnt].l+=m;q[cnt].r+=m;
            }
        n=cnt;
        for(int i=1;i<=n;i++)
        {
            disc[++tot]=q[i].l;disc[++tot]=q[i].r;
        }
        sort(disc+1,disc+tot+1);
        sort(q+1,q+n+1);
        build(1,1,n<<1);
        for(int i=1;i<=n;i++)
        {
            q[i].l=find(q[i].l),q[i].r=find(q[i].r);
        }
        for(int i=1;i<=n;i++)
        {
            update(1,1,q[i].l,q[i].v);
            if(query(1,max(q[i].r-m+1,1),q[i].r)>disc[q[i].r])
            {
                printf("No\n");
                flag=1;
                break;
            }
        }
        if(!flag)printf("Yes\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lvmaooi/article/details/80853726