bzoj3693 圆桌会议(Hall定理+线段树)

题解:传送门
要求任意子集均满足,我们考虑对于每一个区间[p,q](显然只有 Q=ri 时这个区间才有询问的意义,同时我们也有 P=lj ),所有[l,r]在[p,q]之内的a的和s应满足s<=q-p+1即s+p-1<=q,否则一定不满足Hall定理。于是我们把所有的区间按r升序排列,考虑枚举Q,维护 P=Lj 时的答案,我们每次做到区间[l,r]时,所有P=1…l的和s都增大了a,然后我们查询1…r的最大值是否<=r-l+1,用线段树维护即可。
把环复制一遍变成链的情况,注意特判掉询问总区间的情况,具体证明可见神犇blog

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
inline ll read(){
    ll 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 n,m,a[N<<2];
struct quer{
    int l,r,a;
    friend bool operator<(quer a,quer b){return a.r<b.r;}
}q[N<<1];
struct node{
    int mx,add;
}tr[N<<4];
inline void pushup(int p){
    tr[p].mx=max(tr[p<<1].mx,tr[p<<1|1].mx);
}
inline void build(int p,int l,int r){
    tr[p].add=tr[p].mx=0;
    if(l==r){tr[p].mx=a[l]-1;return;}
    int mid=l+r>>1;
    build(p<<1,l,mid);build(p<<1|1,mid+1,r);pushup(p);
}
inline void doadd(int p,int val){
    tr[p].mx+=val;tr[p].add+=val;
}
inline void pushdown(int p){
    if(!tr[p].add) return;
    doadd(p<<1,tr[p].add);doadd(p<<1|1,tr[p].add);tr[p].add=0;
}
inline void add(int p,int l,int r,int x,int y,int val){
    if(x<=l&&r<=y){doadd(p,val);return;}
    int mid=l+r>>1;pushdown(p);
    if(x<=mid) add(p<<1,l,mid,x,y,val);
    if(y>mid) add(p<<1|1,mid+1,r,x,y,val);
    pushup(p);
}
inline int qmax(int p,int l,int r,int x,int y){
    if(x<=l&&r<=y) return tr[p].mx;
    int mid=l+r>>1,res=0;pushdown(p);
    if(x<=mid) res=max(res,qmax(p<<1,l,mid,x,y));
    if(y>mid) res=max(res,qmax(p<<1|1,mid+1,r,x,y));
    return res;
}
int main(){
//  freopen("a.in","r",stdin);
    int tst=read();
    while(tst--){
        n=read();m=read();int sum=0,tot=n;
        for(int i=1;i<=n;++i){
            q[i].l=read()+1,q[i].r=read()+1,q[i].a=read(),sum+=q[i].a;
            if(q[i].l>q[i].r) q[i].r+=m;
            else q[++tot].l=q[i].l+m,q[tot].r=q[i].r+m,q[tot].a=q[i].a;
        }if(sum>m){puts("No");continue;}n=tot;tot=0;
        for(int i=1;i<=n;++i) a[++tot]=q[i].l,a[++tot]=q[i].r;
        sort(a+1,a+tot+1);tot=unique(a+1,a+tot+1)-a-1;
        build(1,1,tot);sort(q+1,q+n+1);bool flag=1;
        for(int i=1;i<=n;++i){
            q[i].l=lower_bound(a+1,a+tot+1,q[i].l)-a;
            q[i].r=lower_bound(a+1,a+tot+1,q[i].r)-a;
            add(1,1,tot,1,q[i].l,q[i].a);int mx=qmax(1,1,tot,1,q[i].r);
            if(mx>a[q[i].r]){flag=0;break;}
        }puts(flag?"Yes":"No");
    }return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值