zoukankan      html  css  js  c++  java
  • 3693: 圆桌会议

    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 }
  • 相关阅读:
    [C/C++]宽字符与控制台程序
    C# 实现屏幕键盘 (SCREENKEYBOARD)
    c#模拟键盘输入
    窗口玻璃特效,半透明窗口,使用DWM实现Aero Glass效果
    DMRS、DRS、SRS、CRS各自作用区别
    LTE的9种传输模式
    在4G通讯技术中什么是ZC根序列,ZC根序列规划的目的和原则是什么?
    為何LTE要先偵測PSS然後再偵測SSS 转自C114
    PSS和SSS用户小区接入的同步过程
    LTE PCI MOD3 规划
  • 原文地址:https://www.cnblogs.com/mjtcn/p/9648260.html
Copyright © 2011-2022 走看看