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; 
}  
posted @ 2018-09-20 08:02  zzzzx  阅读(347)  评论(0编辑  收藏  举报