3693: 圆桌会议
https://www.lydsy.com/JudgeOnline/problem.php?id=3693
分析:
Hall定理+线段树。
如果将桌子放到左边,每组的人拆开放到右边,就成了二分图匹配问题,问是否存在完美匹配。
Hall定理:设二分图中G=<V1,V2,E>中 |V1|=m<=|V2|=n,G中存在从V1到V2的完全匹配当且仅当V1中任意k(k=1,2,...,m)个顶点至少与V2中k个顶点是相邻的。
但是此题中,判断左边所有的Li,Ri就行了。
首先如果左边的桌子没有被一些人选到(即没有边),显然不用考虑。然后只去考虑剩下的点的子集复杂度也是2^n级别的。剩下的许多桌子一定是被一些组的人选到了。考虑一组人选到的桌子Li,Ri,那么这些桌子向右边对部分人连的边是相同的(每个桌子都连向这组的每个人),那么只要判一下这个区间是否满足Ri-Li+1>=Σai(连向右边的点的点数)就行了。这个区间的子集就可以不用考虑了,因为每个点连出的边都一样。然后在查一下多个区间和来的情况,就是最小的l,和最大的r之间。
所以查询的时候只需要查任意的L与任意的R就行了。然后查询就是R-L+1>=s(s为L~R这些点连向右边的点数),R>=s+L-1,然后对于每个Ri查询所有小于Ri的L,是否满足这个式子。线段树维护这个值,每次查询所有小于Li的L的最大值。加入一个Ri,加入一个区间Li~Ri,然后所有的小于Li的L都应更新加上ai,表示L~Ri的向右边连的点数增加了ai。
代码:
1 #include<cstdio>
2 #include<algorithm>
3 #include<cstring>
4 #include<cmath>
5 #include<iostream>
6 #include<cctype>
7 #include<set>
8 #include<vector>
9 #include<queue>
10 #include<map>
11 #define fi(s) freopen(s,"r",stdin);
12 #define fo(s) freopen(s,"w",stdout);
13 using namespace std;
14 typedef long long LL;
15
16 inline int read() {
17 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
18 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
19 }
20
21 const int N = 200005;
22 const int M = 400005;
23 struct Que{
24 int l,r,v;
25 Que() {}
26 Que(int a,int b,int c) { l = a, r = b, v = c; }
27 bool operator < (const Que &A) const {
28 return r < A.r;
29 }
30 }q[N];
31 int Num[N << 1];
32 int mx[M << 2], tag[M << 2];
33
34 #define Root 1, n, 1
35 #define lson l, mid, rt << 1
36 #define rson mid + 1, r, rt << 1 | 1
37
38 void pushup(int rt) {
39 mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]);
40 }
41 void pushdown(int rt) {
42 if (tag[rt]) {
43 mx[rt << 1] += tag[rt]; tag[rt << 1] += tag[rt];
44 mx[rt << 1 | 1] += tag[rt]; tag[rt << 1 | 1] += tag[rt];
45 tag[rt] = 0;
46 }
47 }
48 void build(int l,int r,int rt) {
49 tag[rt] = mx[rt] = 0;
50 if (l == r) {
51 mx[rt] = Num[l] - 1;
52 return;
53 }
54 int mid = (l + r) >> 1;
55 build(lson); build(rson);
56 pushup(rt);
57 }
58 void update(int l,int r,int rt,int L,int R,int v) {
59 if (L <= l && r <= R) {
60 mx[rt] += v; tag[rt] += v;
61 return ;
62 }
63 pushdown(rt);
64 int mid = (l + r) >> 1;
65 if (L <= mid) update(lson, L, R, v);
66 if (R > mid) update(rson, L, R, v);
67 pushup(rt);
68 }
69 int query(int l,int r,int rt,int L,int R) {
70 if (L <= l && r <= R) {
71 return mx[rt];
72 }
73 pushdown(rt);
74 int mid = (l + r) >> 1, res = 0;
75 if (L <= mid) res = query(lson, L, R);
76 if (R > mid) res = max(res, query(rson, L, R));
77 return res;
78 }
79
80 void solve() {
81 int n = read(), m = read();
82 LL sum = 0;
83 int Q = 0;
84 for (int i=1; i<=n; ++i) {
85 int l = read() + 1, r = read() + 1, v = read();
86 q[++Q] = Que(l, r, v);
87 if (l > r) q[Q].r += m;
88 else q[++Q] = Que(l + m, r + m, v);
89 sum += q[Q].v;
90 }
91 if (sum > m) {
92 puts("No"); return ;
93 }
94
95 int cnt = 0;
96 for (int i=1; i<=Q; ++i) Num[++cnt] = q[i].l, Num[++cnt] = q[i].r;
97 sort(Num + 1, Num + cnt + 1);
98 int lim = cnt; cnt = 1;
99 for (int i=2; i<=lim; ++i) if (Num[cnt] != Num[i]) Num[++cnt] = Num[i];
100 for (int i=1; i<=Q; ++i) {
101 q[i].l = lower_bound(Num + 1, Num + cnt + 1, q[i].l) - Num;
102 q[i].r = lower_bound(Num + 1, Num + cnt + 1, q[i].r) - Num;
103 }
104
105 n = cnt;
106 sort(q + 1, q + Q + 1);
107 build(Root);
108 for (int i=1; i<=Q; ++i) {
109 update(Root, 1, q[i].l, q[i].v);
110 if (query(Root, 1, q[i].l) > Num[q[i].r]) {
111 puts("No"); return;
112 }
113 }
114 puts("Yes");
115 }
116 int main() {
117 int T = read();
118 while (T--) solve();
119 return 0;
120 }
来源:https://www.cnblogs.com/mjtcn/p/9648260.html