New Year and Conference【树状数组+哈希】

Codeforces 1284 D


  题意

  有N个会议,有A、B两个会议厅,现在我们有「1,2,3,……,N」这N个元素组成的集合S,现在我们定义ss是S的非空子集,我们要让全体的集合ss满足:所有重叠的会议在AB中同时重叠,或者同时不重叠,这样是开心的(YES),否则都是NO。

  简化一下题意,对于任意两个会议,如果它们在A会议厅中是有重叠的,那么它们在B会议厅也得是重叠的,或者在B中重叠,在A中也是要重叠,或者都是不重叠的,那么就是开心的,否则,均是不开心。现在,我们想知道这个大老板会不会开心呢?

  思路

  想的方法是,如果我们在A中重叠,那么在B中也要重叠,那么对应的每个会议,它在A中包含的重叠元素和它在B中包含的重叠的元素的个数应该是相等的。在这里可以用哈希来维护,首先我们可以想到的自然是N^{2}的暴力来做,但是我们重叠的个数是可以通过树状数组来维护出来的。

  就譬如说,每个会议在A or B中,都会有对应的开会的时间段,我们定义[l, r],那么,我们如果对r端点升序,就可以保证如果l≤r就是冲突的了,可以用树状数组维护,当然,对于那些在这之前的,我们仍然是需要维护,我们可以把不断弹出的,给放到另一个树状数组里去(这次放右端点),记录放进去的哈希总和,然后呢,用总的减去(l - 1)部分,再加上之前求得的对于其后面的贡献,不就是我们所需要的答案了嘛。

  (后面有优化的想法。)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, lsan_A[maxN << 1], lsan_B[maxN << 1], UA, UB, _UP;
struct node
{
    int l, r, id;
    node(int a=0, int b=0):l(a), r(b) {}
    friend bool operator < (node e1, node e2) { return e1.r < e2.r; }
}A[maxN], B[maxN];
ull hash_ith[maxN], A_id_hash[maxN], B_id_hash[maxN], t[2][maxN << 1], all_A, all_B, all;
inline void update(ull *trie, int x, ull val)
{
    while(x <= _UP)
    {
        trie[x] += val;
        x += lowbit(x);
    }
}
inline ull query(ull *trie, int x)
{
    ull sum = 0;
    while(x)
    {
        sum += trie[x];
        x -= lowbit(x);
    }
    return sum;
}
inline void pre_did()
{
    hash_ith[1] = 1;
    for(int i=2; i<=N; i++)   //每一个id都有一个对应的hash值
    {
        hash_ith[i] = hash_ith[i - 1] * (ull)3;
    }
}
int main()
{
    scanf("%d", &N);
    pre_did();
    for(int i=1; i<=N; i++)
    {
        scanf("%d%d%d%d", &A[i].l, &A[i].r, &B[i].l, &B[i].r); A[i].id = i; B[i].id = i;
        lsan_A[2 * i - 1] = A[i].l; lsan_A[2 * i] = A[i].r;
        lsan_B[2 * i - 1] = B[i].l; lsan_B[2 * i] = B[i].r;
    }
    sort(lsan_A + 1, lsan_A + 2 * N + 1);
    sort(lsan_B + 1, lsan_B + 2 * N + 1);
    UA = (int)(unique(lsan_A + 1, lsan_A + 2 * N + 1) - lsan_A - 1);
    UB = (int)(unique(lsan_B + 1, lsan_B + 2 * N + 1) - lsan_B - 1);
    _UP = max(UA, UB);
    for(int i=1; i<=N; i++)
    {
        A[i].l = (int)(lower_bound(lsan_A + 1, lsan_A + UA + 1, A[i].l) - lsan_A);
        A[i].r = (int)(lower_bound(lsan_A + 1, lsan_A + UA + 1, A[i].r) - lsan_A);
        B[i].l = (int)(lower_bound(lsan_B + 1, lsan_B + UB + 1, B[i].l) - lsan_B);
        B[i].r = (int)(lower_bound(lsan_B + 1, lsan_B + UB + 1, B[i].r) - lsan_B);
    }
    sort(A + 1, A + N + 1);
    sort(B + 1, B + N + 1);
    bool flag = true;
    for(int i=1; i<=N; i++) update(t[0], A[i].l, hash_ith[A[i].id]);
    all = 0;
    for(int i=1; i<=N; i++)
    {
        update(t[0], A[i].l, -hash_ith[A[i].id]);
        A_id_hash[A[i].id] = query(t[0], A[i].r) + (all - query(t[1], A[i].l - 1));
        all += hash_ith[A[i].id];
        update(t[1], A[i].r, hash_ith[A[i].id]);
    }
    memset(t, 0, sizeof(t));
    for(int i=1; i<=N; i++) update(t[0], B[i].l, hash_ith[B[i].id]);
    all = 0;
    for(int i=1; i<=N; i++)
    {
        update(t[0], B[i].l, -hash_ith[B[i].id]);
        B_id_hash[B[i].id] = query(t[0], B[i].r) + (all - query(t[1], B[i].l - 1));
        all += hash_ith[B[i].id];
        update(t[1], B[i].r, hash_ith[B[i].id]);
    }
    for(int i=1; i<=N; i++) if(A_id_hash[i] ^ B_id_hash[i]) { flag = false; break; }
    printf(flag ? "YES\n" : "NO\n");
    return 0;
}

  当然,这题是可以优化的,我们没有必要去开两个树状数组来维护这个,我们甚至可以只用一个树状数组(也就是不需要加入算之前贡献的这部分)。

  我们可以考虑成,我们现在想知道求每两个点之间的关系了,但是呢,之前求的是对于每个点它们的冲突点的集合的哈希。也就是a->b,我们还要来算一遍b->a,我们如果将点贡献乘以它的值,那么岂不是将{a->b、b->a}变成了{a--b}这样的形式了嘛。于是乎,我们只需要在对之后点的贡献算答案的时候,我们再乘以它自己的hash值,就可以做到这个了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, lsan_A[maxN << 1], lsan_B[maxN << 1], UA, UB, _UP;
struct node
{
    int l, r, id;
    node(int a=0, int b=0):l(a), r(b) {}
    friend bool operator < (node e1, node e2) { return e1.r < e2.r; }
}A[maxN], B[maxN];
ull hash_ith[maxN], A_id_hash[maxN], B_id_hash[maxN], t[2][maxN << 1], all_A, all_B;
inline void update(ull *trie, int x, ull val)
{
    while(x <= _UP)
    {
        trie[x] += val;
        x += lowbit(x);
    }
}
inline ull query(ull *trie, int x)
{
    ull sum = 0;
    while(x)
    {
        sum += trie[x];
        x -= lowbit(x);
    }
    return sum;
}
inline void pre_did()
{
    hash_ith[1] = 1;
    for(int i=2; i<=N; i++)   //每一个id都有一个对应的hash值
    {
        hash_ith[i] = hash_ith[i - 1] * (ull)3;
    }
}
int main()
{
    scanf("%d", &N);
    pre_did();
    for(int i=1; i<=N; i++)
    {
        scanf("%d%d%d%d", &A[i].l, &A[i].r, &B[i].l, &B[i].r); A[i].id = i; B[i].id = i;
        lsan_A[2 * i - 1] = A[i].l; lsan_A[2 * i] = A[i].r;
        lsan_B[2 * i - 1] = B[i].l; lsan_B[2 * i] = B[i].r;
    }
    sort(lsan_A + 1, lsan_A + 2 * N + 1);
    sort(lsan_B + 1, lsan_B + 2 * N + 1);
    UA = (int)(unique(lsan_A + 1, lsan_A + 2 * N + 1) - lsan_A - 1);
    UB = (int)(unique(lsan_B + 1, lsan_B + 2 * N + 1) - lsan_B - 1);
    _UP = max(UA, UB);
    for(int i=1; i<=N; i++)
    {
        A[i].l = (int)(lower_bound(lsan_A + 1, lsan_A + UA + 1, A[i].l) - lsan_A);
        A[i].r = (int)(lower_bound(lsan_A + 1, lsan_A + UA + 1, A[i].r) - lsan_A);
        B[i].l = (int)(lower_bound(lsan_B + 1, lsan_B + UB + 1, B[i].l) - lsan_B);
        B[i].r = (int)(lower_bound(lsan_B + 1, lsan_B + UB + 1, B[i].r) - lsan_B);
    }
    sort(A + 1, A + N + 1);
    sort(B + 1, B + N + 1);
    all_A = all_B = 0;
    for(int i=N; i>=1; i--)
    {
        all_A += hash_ith[A[i].id] * query(t[0], A[i].r);
        update(t[0], A[i].l, hash_ith[A[i].id]);
    }
    for(int i=N; i>=1; i--)
    {
        all_B += hash_ith[B[i].id] * query(t[1], B[i].r);
        update(t[1], B[i].l, hash_ith[B[i].id]);
    }
    printf(all_A == all_B ? "YES\n" : "NO\n");
    return 0;
}
发布了722 篇原创文章 · 获赞 891 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/103842772