1月14日 并查集专项训练(补题仍未完成)

A.Trails and Glades(未完成)

 

B.Two Sets(赛后完成)

题意:题目给n个数字,询问能否将n个数字分入两个集合A、B。

    对于集合A,X和a - X 同属于 集合A。

    对于集合B,X和b - X 同属于 集合B。

思路:A!=B时,

    反向思考,如果 a - X 不存在  , 那么 X 只能放入 B 集合中 (假定集合成立)

         如果 b - X 不存在 ,  那么 X 只能放入 A 集合中 (假定集合成立)

    将 n + 1 作为 集合A 的根节点 , 将 n + 2 作为 集合B 的根节点

    1.    

    如果 a - X 不存在 , bset(X ,n + 2);将 X 并入 集合B 中

    如果 b - X 不存在 , bset(X ,n + 1);将 X 并入 集合A 中

    2.

    如果 a - X 存在 ,则将 X 和 a - X 合并起来,但是不代表 X 和 a - X 属于集合A

    如果 a - X 存在 , b - X 不存在 , 将 X 并入 集合A 中

    3.

    如果 a - X 存在 并且 b - X 存在 , 则说明 X 需要同时属于 集合A 和 集合B , 肯定不符合题目要求

    如果 a - X 不存在 并且 b - X 不存在 , 则说明 X 需要同时不属于 集合A 和 集合B , 肯定不符合题目要求

     

    当所求集合满足题目条件的时候 , 集合A 的祖先 和 集合B 的祖先 必然不同

    相反 , 当集合A的祖先和集合B祖先相同时,题目条件必定不成立 

   A==B时

    只要满足n个数字都属于其中一个集合即可。

    那么只要 X 和 a - X都存在 , 那么必定可以将n个数字放入其中一个集合

#include<cstdio>
#include<string.h>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<vector>
#include<queue>
#include<set>
#include<stack>
#include<map>
#include<cctype>
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define mem(a,x) memset(a,x,sizeof(a))
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid + 1,r
#define P pair<int, int>
#define ull unsigned long long
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
const ll mod = 998244353;
const int inf = 0x3f3f3f3f;
const long long INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-7;
ll GCD(ll a, ll b) { while (b ^= a ^= b ^= a %= b); return a; }
ll LCM(ll a, ll b) { return a * b / GCD(a, b); }
ll prime[maxn] = { 0 }, num_prime = 0;
int isNotPrime[maxn] = { 1 , 1 };
inline ll read()
{
    ll X = 0, w = 0; char ch = 0;
    while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
    while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
    return w ? -X : X;
}
inline void write(int x)
{
    if (x < 0) putchar('-'), x = -x;
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}
void isPrime()
{
    for (int i = 2; i < maxn; ++i)
    {
        if (!isNotPrime[i]) prime[num_prime++] = i;
        for (int j = 0; j < num_prime && i * prime[j] < maxn; ++j)
        {
            isNotPrime[i * prime[j]] = 1;
            if (!i % prime[j]) break;
        }
    }
    printf("%lld", prime[num_prime - 1]);
}
ll binaryPow(ll a, ll b, ll c) {
    ll ans = 1;
    while (b > 0) {
        if (b & 1) {
            ans = ans * a % c;
        }
        a = a * a % c;
        b >>= 1;
    }
    return ans % c;
}
void BUG()
{
    printf("DEBUG\n");
}

ll n, a, b;
ll arr[maxn];
map<ll, ll>mp;
int f[maxn];
int find(int x)
{
    return x == f[x] ? x : f[x] = find(f[x]);
}
void bset(int x, int y)
{
    int fx = find(x);
    int fy = find(y);
    f[fx] = fy;
}


int main()
{
    scanf("%lld %lld %lld", &n, &a, &b);
    for (int i = 1; i <= n + 2; ++i)
        f[i] = i;
    for (int i = 1; i <= n; ++i)
    {
        scanf("%lld", &arr[i]);
        mp[arr[i]] = i;
    }
    for (int i = 1; i <= n; ++i)
    {
        if (mp.count(a - arr[i])) bset(i, mp[a - arr[i]]);
        else bset(i, n + 2);
        if (mp.count(b - arr[i])) bset(i, mp[b - arr[i]]);
        else bset(i, n + 1);
    }
    if (find(n + 1) == find(n + 2))
    {
        printf("NO\n");
    }
    else
    {
        printf("YES\n");
        for (int i = 1; i <= n; ++i)
        {
            if (find(i) == find(n + 1))
                printf("0");
            else
                printf("1");
            if (i == n) 
                printf("\n");
            else
                printf(" ");
        }
    }
    return 0;
}
View Code

C.Destroying Array(赛后完成)

题意:给出n个数字ai , 再给出n个数字表示销毁n个数据的顺序 , 询问每次消除数据之后,序列中最大的区间和是多少

思路:反向思维

   将消除数据,转变为依次添加数据,并求出序列中最大的区间和

   每次添加数据a[pos] ,并将 并查集 a[pos - 1] 和 a[pos + 1] 合并到 a[pos] 中 来更新区间和 ,通过与上一次最大区间和进行比较获取本次最大区间和

#include<cstdio>
#include<string.h>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<vector>
#include<queue>
#include<set>
#include<stack>
#include<map>
#include<cctype>
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define mem(a,x) memset(a,x,sizeof(a))
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid + 1,r
#define P pair<int, int>
#define ull unsigned long long
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
const ll mod = 998244353;
const int inf = 0x3f3f3f3f;
const long long INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-7;
ll GCD(ll a, ll b) { while (b ^= a ^= b ^= a %= b); return a; }
ll LCM(ll a, ll b) { return a * b / GCD(a, b); }
ll prime[maxn] = { 0 }, num_prime = 0;
int isNotPrime[maxn] = { 1 , 1 };
inline ll read()
{
    ll X = 0, w = 0; char ch = 0;
    while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
    while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
    return w ? -X : X;
}
inline void write(int x)
{
    if (x < 0) putchar('-'), x = -x;
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}
void isPrime()
{
    for (int i = 2; i < maxn; ++i)
    {
        if (!isNotPrime[i]) prime[num_prime++] = i;
        for (int j = 0; j < num_prime && i * prime[j] < maxn; ++j)
        {
            isNotPrime[i * prime[j]] = 1;
            if (!i % prime[j]) break;
        }
    }
    printf("%lld", prime[num_prime - 1]);
}
ll binaryPow(ll a, ll b, ll c) {
    ll ans = 1;
    while (b > 0) {
        if (b & 1) {
            ans = ans * a % c;
        }
        a = a * a % c;
        b >>= 1;
    }
    return ans % c;
}
void BUG()
{
    printf("DEBUG\n");
}

ll brr[maxn];
ll n, m;
ll arr[maxn];
ll ans[maxn];
ll crr[maxn];
ll f[maxn];
ll visit[maxn];
int find(int x)
{
    return x == f[x] ? x : f[x] = find(f[x]);
}
void bset(int x, int y)
{
    int fx = find(x), fy = find(y);
    f[fx] = fy;
}
int main()
{
    scanf("%lld", &n);
    for (int i = 0; i <= 2 * n; ++i)
    {
        f[i] = i;
        crr[i] = 0;
        visit[i] = 0;
    }
    for (int i = 1; i <= n; ++i)
    {
        scanf("%lld", &arr[i]);
    }
    for (int i = n; i >= 1; --i)
    {
        scanf("%lld", &brr[i]);
    }
    ans[0] = 0;
    for (int i = 1; i <= n; ++i)
    {
        ll pos = brr[i];
        visit[pos] = 1;
        ll l = pos - 1;
        ll r = pos + 1;
        ll tmp = arr[pos];
        if (visit[l] != 0 && l >= 1)
        {
            l = find(l);
            tmp += crr[l];
            bset(l, pos);
        }
        if (visit[r] != 0 && r <= n)
        {
            r = find(r);
            tmp += crr[r];
            bset(r, pos);
        }
        crr[pos] = tmp;
        ans[i] = max(ans[i - 1], tmp);
    }
    for (int i = n - 1; i >= 0; --i)
    {
        printf("%lld\n", ans[i]);
    }
    return 0;
}
View Code

D.Chemical table(未完成)

E.Gourmet choice(未完成)

F.The LCMs Must be Large(未完成)

G.Zjnu Stadium(赛后完成)

题意:有n个节点,m个询问,询问存在 ans 个 询问为假 (和之前给出的询问所得到的条件相冲突)

思路:带权并查集模板题

#include<cstdio>
#include<string.h>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<vector>
#include<queue>
#include<set>
#include<stack>
#include<map>
#include<cctype>
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define mem(a,x) memset(a,x,sizeof(a))
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid + 1,r
#define P pair<int, int>
#define ull unsigned long long
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
const ll mod = 998244353;
const int inf = 0x3f3f3f3f;
const long long INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-7;
ll GCD(ll a, ll b) { while (b ^= a ^= b ^= a %= b); return a; }
ll LCM(ll a, ll b) { return a * b / GCD(a, b); }
ll prime[maxn] = { 0 }, num_prime = 0;
int isNotPrime[maxn] = { 1 , 1 };
inline ll read()
{
    ll X = 0, w = 0; char ch = 0;
    while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
    while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
    return w ? -X : X;
}
inline void write(int x)
{
    if (x < 0) putchar('-'), x = -x;
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}
void isPrime()
{
    for (int i = 2; i < maxn; ++i)
    {
        if (!isNotPrime[i]) prime[num_prime++] = i;
        for (int j = 0; j < num_prime && i * prime[j] < maxn; ++j)
        {
            isNotPrime[i * prime[j]] = 1;
            if (!i % prime[j]) break;
        }
    }
    printf("%lld", prime[num_prime - 1]);
}
ll binaryPow(ll a, ll b, ll c) {
    ll ans = 1;
    while (b > 0) {
        if (b & 1) {
            ans = ans * a % c;
        }
        a = a * a % c;
        b >>= 1;
    }
    return ans % c;
}
void BUG()
{
    printf("DEBUG\n");
}

ll value[maxn];
ll f[maxn];
ll ans = 0;
int find(int x)
{
    if (x != f[x])
    {
        int t = f[x];
        f[x] = find(f[x]);
        value[x] += value[t];
    }
    return f[x];
}

void bset(int x, int y ,int v)
{
    int fx = find(x);
    int fy = find(y);
    if (fx != fy)
    {
        f[fx] = fy;
        value[fx] = value[y] - value[x] + v;
    }
    else
    {
        if (value[x] - value[y] != v)
        {
            ans++;
        }
    }
}

int main()
{
    int n, m;
    while (~scanf("%d %d",&n,&m))
    {
        ans = 0;
        for (int i = 1; i <= n; ++i)
        {
            f[i] = i;
            value[i] = 0;
        }
        for (int i = 1; i <= m; ++i)
        {
            int a, b, c;
            scanf("%d %d %d", &a, &b, &c);
            bset(a, b ,c);
        }
        cout << ans << endl;
    }
    

    return 0;
}
View Code

一个从很久以前就开始做的梦。

猜你喜欢

转载自www.cnblogs.com/DreamACMer/p/12190152.html