"Weighted disjoint-set" parity game

Parity games

Link to the original question: parity game

Subject to the effect

Give you N intervals, each interval you give it parity with 1, which ask you to ask the logic of conflict

Topic solution to a problem

A question with a set of weights and check, let me check with right and set a deeper understanding, and with the right to check the set can be divided into two (in the middle of this question)

  • "Sideband power" disjoint-set
  • "Extension field" disjoint-set

Both methods are caused by differences in thinking, in which the first solution is the most common, in the second solution is the easiest code to achieve, let's be explored for the first

Sideband right, obviously, we want to operate a store right side of the edge disjoint-set, we here use d to represent the value of the current node to the root node Xor, what does that mean, and how to maintain it? Means that we are the same for each side of the storage is connected to two belong to the same parity, the right side is 0, 1 is different, then all the edge weights our unique path from the root node to all x Xor up, you can determine whether the x node and the root node of the same parity, so we can judge for any two points, x and y Xor node to the root node to the root node Xor Xor value up to get the value is that we need to Xor value between any two points, then our current interrogation and parity were Xor, if the conflict is an explanation, if the value of 0 indicates no conflicts

That being done to solve our query, we will solve the problem of the merger, then the last paragraph continues, we currently have x, y two points, and their roots p, q, q make the connection to the p child nodes, then we are asking is d [p] a, d [p] how demand? We now known information d [x] and d [y] is x ~ p and y ~ q, we are asking that p ~ q, we know x ~ y by x ~ p, y ~ q , p ~ q to the composition, then the parity of xy (here by \ (cnt_ {x, y} \) to represent any two of the parity, the parity how come? gave input) \ ( cnt_ {x, y} = d [x] Xord [y] Xord [p] \) then we can get \ (d [p] = d [x] Xord [y] Xorans_ {x, y} \) of , then merge operation is complete.

After completion of the two, we have to analyze the problem itself, because this question is given in a range, rather than a point, so we have to be converted to point interval, the interval into a point? I feel very familiar with? Yes, indeed we are very familiar with the defense used a similar method in this question is to use the prefix and save parity, what does that mean? Details can be seen on top of that question, I will not repeat them here, transformed into this question up, since we want to convert to a point, this is certainly not the data range, we consider discrete.

So after discretization, we get a sequence, this sequence is tightly next point, and here we will be able to get through the above transfer point range, for example, we now want to merge a range \ (l, r \ ) , it actually \ (l, r \) parity is already known, and (a lot of people stuck in here, do not know how to operate here, there are a lot of people did not think with disjoint-set to maintain .. , the routine on the card), then \ (l - 1 \) to a certain value of the parity of the foregoing are also known constant, then we will \ (R & lt \) and \ (l - 1 \) with and Charles set maintenance (think about why? the answer is obviously), so that we maintain the parity of the two sections and the two sections merge.

Based on the above information, we've had this question, the following code

//#define fre yes

#include <cstdio>
#include <algorithm>

const int N = 20005;
int ele[N << 1];
struct message {
    int l, r, ans;
} arr[N];

bool flag;
namespace Union {
    int par[N], d[N];
    inline void init(int n) {
        for (int i = 1; i <= n; i++) {
            par[i] = i;
        }
    }
    
    int find(int x) {
        if(par[x] == x) return par[x];
        int rt = find(par[x]);
        d[x] ^= d[par[x]];
        return par[x] = rt;
    }
    
    inline void unite(int x, int y, int a, int b, int i) {
        par[a] = b;
        d[a] = d[x] ^ d[y] ^ arr[i].ans;
    }
    
    inline void solve(int x, int y, int i) {
        if((d[x] ^ d[y]) != arr[i].ans) {
            printf("%d\n", i - 1);
            flag = 1;
        } 
    }
}

int m;
inline void discrete(int n) {
    std::sort(ele + 1, ele + 1 + n * 2);
    m = std::unique(ele + 1, ele + 1 + n * 2) - ele - 1;
}

int ask(int x) {
    return std::lower_bound(ele + 1, ele + 1 + m, x) - ele;
}

int main() {
    static int n, T;
    scanf("%d %d", &T, &n);
    for (int i = 1; i <= n; i++) {
        int x, y; char c[6];
        scanf("%d %d %s", &x, &y, c + 1);
        arr[i].l = x; arr[i].r = y;
        arr[i].ans = (c[1] == 'e' ? 0 : 1);
        ele[i] = x - 1; ele[i + n] = y;
    } 
    
    discrete(2 * n);
    Union::init(m);
    
    for (int i = 1; i <= n; i++) {
        int x = ask(arr[i].l - 1);
        int y = ask(arr[i].r);
        int p = Union::find(x), q = Union::find(y);
        if(p == q) {
            Union::solve(x, y, i);
            if(flag) return 0;
        } else Union::unite(x, y, p, q, i);
    } printf("%d\n", n);
    return 0;
}

Then let us discuss the second method, an extension field disjoint-set, the second method is more simple thinking, the code is easier to implement because it would not involve operations such knowledge in place, how to operate it?

Each node \ (X \) is split into two nodes, \ (ODD X_ {} \) and \ (x_ {even} \) represent the sum [x] is an odd number and the sum [x] is even, we often Add these two nodes x becomes the "odd field" and "even field."

Then there will be the following case, the discrete set \ (l - 1 \) and \ (R & lt \) values are \ (X \) and \ (Y \) , provided \ (CNT \) of two parity (here, read only)

  • If the merge cnt = 0 \ (x_ {odd} \) and \ (ODD Y_ {} \) , \ (the even X_ {} \) and \ (the even Y_ {} \) . This means that "x is odd" and "y is an odd number," can be introduced to each other, "x is an even number" and "y is an even number" may be introduced to each other, they are equivalent information.
  • If the merge cnt = 0 \ (x_ {odd} \) and \ (the even Y_ {} \) , \ (the even X_ {} \) and \ (ODD Y_ {} \) . This means that "x is odd" and "y is an even number," can be introduced to each other, "x is an even number" and "y is an odd number" may be introduced to each other, they are equivalent information. (Why can launch each other? May ask yourself)

The combined also maintains the above-described relationship of the transmission, after handling (x, y, 0) (y, z, 1) and two relationships, it is clear that x, z are also obvious relationship, this approach is quite to maintain the connectivity between nodes on the map in the absence, but expanded to cope with a plurality of fields more transfer relationship

If the x, y corresponding to \ (x_ {odd} \) and \ (y_ {odd} \) in the same set, it means that both have the same parity, if x, y corresponding to \ (x_ {odd} \) and \ (y_ {even} \) in the same set, it is known that different parity both

So the above information, we can get the code, the code is as follows

//#define fre yes

#include <cstdio>
#include <algorithm>

const int N = 20005;
int ele[N << 1];
struct message {
    int l, r, ans;
} arr[N];

bool flag;
namespace Union {
    int par[N], d[N];
    inline void init(int n) {
        for (int i = 1; i <= n; i++) {
            par[i] = i;
        }
    }
    
    int find(int x) {
        if(par[x] == x) return par[x];
        return par[x] = find(par[x]);
    }
    
    inline void unite(int x, int y) {
        int a = find(x);
        int b = find(y);
        if(a == b) return ;
        
        par[a] = b;
    }
}

int m;
inline void discrete(int n) {
    std::sort(ele + 1, ele + 1 + n * 2);
    m = std::unique(ele + 1, ele + 1 + n * 2) - ele - 1;
}

int ask(int x) {
    return std::lower_bound(ele + 1, ele + 1 + m, x) - ele;
}

int main() {
    static int n, T;
    scanf("%d %d", &T, &n);
    for (int i = 1; i <= n; i++) {
        int x, y; char c[6];
        scanf("%d %d %s", &x, &y, c + 1);
        arr[i].l = x; arr[i].r = y;
        arr[i].ans = (c[1] == 'e' ? 0 : 1);
        ele[i] = x - 1; ele[i + n] = y;
    } 
    
    discrete(2 * n);
    Union::init(m * 2);
    
    for (int i = 1; i <= n; i++) {
        int x = ask(arr[i].l - 1);
        int y = ask(arr[i].r);
        int x_odd = x, x_even = x + m;
        int y_odd = y, y_even = y + m;
        if(arr[i].ans == 0) {
            if(Union::find(x_odd) == Union::find(y_even)) {
                printf("%d\n", i - 1);
                return 0;
            }
            
            Union::unite(x_odd, y_odd);
            Union::unite(x_even, y_even);
        } else {
            if(Union::find(x_odd) == Union::find(y_odd)) {
                printf("%d\n", i - 1);
                return 0;
            }
            
            Union::unite(x_odd, y_even);
            Union::unite(x_even, y_odd);
        }
    } printf("%d\n", n);
    return 0;
}

Guess you like

Origin www.cnblogs.com/Nicoppa/p/11576748.html