bzoj3693: 圆桌会议 二分图 hall定理
[TOC]
#题目链接
bzoj3693: 圆桌会议
#题解
对与每个人构建二分,问题化为时候有一个匹配取了所有的人
Hall定理——对于任意的二分图G,G的两个部分为X={x1,x2,…,xn}和Y={y1,y2,…,ym},
存在一个匹配M使得|M|=|X|的充要条件为对于X的任意一个子集A,与A相邻的点集记为T(A),一定有|T(A)|≥|A|
拆环为链
对于任意的区间[L,R],长度R-L+1,将所有区间[L,R]内的组插入操作求和为sum,如果sum > R - L + 1,显然不存在满足条件的匹配,否则一定存在解
对于有意义的区间[L,R]一定在给出的操作区间上
sum > R - L + 1 也就是 sum + P - 1 > Q
前面那部分线段树维护
对于每个右端点询问区间,每次把ai的值加到左端点上
对于右端点扫过去就行了
#代码
/*
对与每个人构建二分,问题化为时候有一个匹配取了所有的人
> Hall定理——对于任意的二分图G,G的两个部分为X={x1,x2,…,xn}和Y={y1,y2,…,ym},
存在一个匹配M使得|M|=|X|的充要条件为对于X的任意一个子集A,与A相邻的点集记为T(A),一定有|T(A)|≥|A|
拆环为链
对于任意的区间[L,R],长度R-L+1,将所有区间[L,R]内的组插入操作求和为sum,如果sum > R - L + 1,显然不存在满足条件的匹配,否则一定存在解
对于有意义的区间[L,R]一定在给出的操作区间上
sum > R - L + 1 也就是 sum + P - 1 > Q
前面那部分线段树维护
对于每个右端点询问区间,每次把ai的值加到左端点上
对于右端点扫过去就行了
*/
#include<map>
#include<vector>
#include<cstdio>
#include<algorithm>
#define gc getchar()
#define pc putchar
#define LL long long
inline int read() {
int x = 0,f = 1;
char c = gc;
while(c < '0' || c > '9')c = gc;
while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = gc;
return x * f;
}
void print(int x) {
if(x < 0) {
pc('-');
x = -x;
}
if(x >= 10) print(x / 10);
pc(x % 10 + '0');
}
const int maxn = 1000007;
struct Q {
int l,r,v;
bool operator < (const Q & k)const {
return r < k.r;
}
} q[maxn];
int d[maxn],cnt ,num;
int mx[maxn << 1],tag[maxn << 1];
int n,m;
#define ls x << 1,l,mid
#define rs x << 1 | 1,mid + 1,r
void update(int x) {
mx[x] = std::max(mx[x << 1],mx[x << 1 | 1]);
}
void build(int x,int l,int r) {
mx[x] = tag[x] = 0;
if(l == r) {
mx[x] = d[l] - 1; return;
}
int mid = l + r >> 1;
build(ls);
build(rs);
update(x);
}
inline void pushdown(int x) {
if(!tag[x]) return;
tag[x << 1] += tag[x]; tag[x << 1 | 1] += tag[x];
mx[x << 1] += tag[x]; mx[x << 1 | 1] += tag[x];
tag[x] = 0;
}
void modify(int x,int l,int r,int L,int R,int val) {
if(L <= l && R >= r) {
tag[x] += val,mx[x] += val;
return;
}
pushdown(x);
int mid = l + r >> 1;
if(L <= mid) modify(ls,L,R,val);
if(R > mid) modify(rs,L,R,val);
update(x);
}
int query(int x,int l,int r,int L,int R) {
if(l >= L && R >= r) return mx[x];
pushdown (x);
int mid = l + r >> 1,ans = 0;
if(L <= mid) ans = std::max(query(ls,L,R),ans);
if(R > mid) ans = std::max(query(rs,L,R),ans);
return ans;
}
int main() {
int T = read();
for(int t = 1;t <= T;t += 1) {
cnt = num = 0;
n = read(),m = read();
bool flag = false;
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) {
puts("No"); 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) d[++ num] = q[i].l,d[++ num] = q[i].r;
std::sort(d + 1,d + num + 1);
std::sort(q + 1,q + n + 1);
build(1,1,n << 1);
for(int i = 1;i <= n;++ i)
q[i].l = std::lower_bound(d + 1,d + num + 1,q[i].l) - d,
q[i].r = std::lower_bound(d + 1,d + num + 1,q[i].r) - d;
for(int i = 1;i <= n;++ i) {
modify(1,1,n << 1,1,q[i].l,q[i].v);
//int k = query(1,1,n << 1,std::max(q[i].r - m + 1,1),q[i].r);
//print(k); pc('\n');
if(query(1,1,n << 1,std::max(q[i].r - m + 1,1),q[i].r) > d[q[i].r]) {
flag = true;
break;
}
}
puts(flag ? "No" : "Yes");
}
return 0;
}