Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 找到无法赢得比赛的玩家数量?_Algorithm_Math_Data Structures_Fenwick Tree - Fatal编程技术网

Algorithm 找到无法赢得比赛的玩家数量?

Algorithm 找到无法赢得比赛的玩家数量?,algorithm,math,data-structures,fenwick-tree,Algorithm,Math,Data Structures,Fenwick Tree,我们被赋予n名玩家,每个玩家有3个A、B和C值。 如果存在另一名玩家j且该玩家的3个值均为A[j]>A[i]、B[j]>B[i]和C[j]>C[i],则该玩家i无法获胜我们被要求找出无法获胜的玩家数量。 我用蛮力尝试了这个问题,蛮力是对玩家数组的线性搜索。但是它显示出了TLE 对于每个玩家i,我将遍历整个数组,以查找是否存在上述条件成立的任何其他玩家j 代码: int count_players_cannot_win(vector<vector<int>> values)

我们被赋予n名玩家,每个玩家有3个A、B和C值。

如果存在另一名玩家j且该玩家的3个值均为A[j]>A[i]、B[j]>B[i]和C[j]>C[i],则该玩家i无法获胜我们被要求找出无法获胜的玩家数量。

我用蛮力尝试了这个问题,蛮力是对玩家数组的线性搜索。但是它显示出了TLE

对于每个玩家i,我将遍历整个数组,以查找是否存在上述条件成立的任何其他玩家j

代码:

int count_players_cannot_win(vector<vector<int>> values) {
    int c = 0;
    int n = values.size();
    for(int i = 0; i < n; i++) {
        for(int j = 0; j!= i && j < n; j++) {
            if(values[i][0] < values[j][0] && values[i][1] < values[j][1] && values[i][2] < values[j][2]) { 
                c += 1;
                break;
           }
        }    
    }
    return c;
}
n(number of players) <= 10^5
int n;
const int N = 4e5 + 1;
int tree[N];

int get_max(int i, int l, int r, int L) {  // range query of max in range v[B+1: n]
    if(r < L || n <= l)
        return numeric_limits<int>::min();
    else if(L <= l)
        return tree[i];
    int m = (l + r)/2;
    return max(get_max(2*i+1, l, m, L), get_max(2*i+2, m+1, r, L));
}
void update(int i, int l, int r, int on, int v) { // point update in tree[on]
    if(r < on || on < l) 
        return;
    else if(l == r) {
        tree[i] = max(tree[i], v);
        return;
    }
    int m = (l + r)/2;
    update(2*i+1, l, m, on, v);
    update(2*i+2, m + 1, r, on, v);
    tree[i] = max(tree[2*i+1], tree[2*i+2]);
}

bool comp(vector<int> a, vector<int> b) {
    return a[0] != b[0] ? a[0] > b[0] : a[1] < b[1];  
}

int solve(vector<vector<int>> &v) {
    n = v.size();
    vector<int> b(n, 0);           // reduce the scale of range from [0,10^9] to [0,10^5]
    for(int i = 0; i < n; i++) {
        b[i] = v[i][1];
    }
    for(int i = 0; i < n; i++) {
        cin >> v[i][2];
    }

//     sort on 0th col in reverse order
    sort(v.begin(), v.end(), comp);
    sort(b.begin(), b.end());
    
    int ans = 0;
    for(int i = 0; i < n;) {
        int j = i;
        while(j < n &&  v[j][0] == v[i][0]) {    
            int B = v[j][1];
            int pos = lower_bound(b.begin(), b.end(), B) - b.begin(); // position of B in b[]
            int mx = get_max(0, 0, n - 1, pos + 1);
            if(mx > v[j][2])
                ans += 1;
            j++;
        }
        while(i < j) {
            int B = v[i][1];
            int C = v[i][2];
            int pos = lower_bound(b.begin(), b.end(), B) - b.begin(); // position of B in b[]
            update(0, 0, n - 1, pos, C);
            i++;
        }
    }
    return ans;
}
约束条件:

int count_players_cannot_win(vector<vector<int>> values) {
    int c = 0;
    int n = values.size();
    for(int i = 0; i < n; i++) {
        for(int j = 0; j!= i && j < n; j++) {
            if(values[i][0] < values[j][0] && values[i][1] < values[j][1] && values[i][2] < values[j][2]) { 
                c += 1;
                break;
           }
        }    
    }
    return c;
}
n(number of players) <= 10^5
int n;
const int N = 4e5 + 1;
int tree[N];

int get_max(int i, int l, int r, int L) {  // range query of max in range v[B+1: n]
    if(r < L || n <= l)
        return numeric_limits<int>::min();
    else if(L <= l)
        return tree[i];
    int m = (l + r)/2;
    return max(get_max(2*i+1, l, m, L), get_max(2*i+2, m+1, r, L));
}
void update(int i, int l, int r, int on, int v) { // point update in tree[on]
    if(r < on || on < l) 
        return;
    else if(l == r) {
        tree[i] = max(tree[i], v);
        return;
    }
    int m = (l + r)/2;
    update(2*i+1, l, m, on, v);
    update(2*i+2, m + 1, r, on, v);
    tree[i] = max(tree[2*i+1], tree[2*i+2]);
}

bool comp(vector<int> a, vector<int> b) {
    return a[0] != b[0] ? a[0] > b[0] : a[1] < b[1];  
}

int solve(vector<vector<int>> &v) {
    n = v.size();
    vector<int> b(n, 0);           // reduce the scale of range from [0,10^9] to [0,10^5]
    for(int i = 0; i < n; i++) {
        b[i] = v[i][1];
    }
    for(int i = 0; i < n; i++) {
        cin >> v[i][2];
    }

//     sort on 0th col in reverse order
    sort(v.begin(), v.end(), comp);
    sort(b.begin(), b.end());
    
    int ans = 0;
    for(int i = 0; i < n;) {
        int j = i;
        while(j < n &&  v[j][0] == v[i][0]) {    
            int B = v[j][1];
            int pos = lower_bound(b.begin(), b.end(), B) - b.begin(); // position of B in b[]
            int mx = get_max(0, 0, n - 1, pos + 1);
            if(mx > v[j][2])
                ans += 1;
            j++;
        }
        while(i < j) {
            int B = v[i][1];
            int C = v[i][2];
            int pos = lower_bound(b.begin(), b.end(), B) - b.begin(); // position of B in b[]
            update(0, 0, n - 1, pos, C);
            i++;
        }
    }
    return ans;
}
n(玩家数量)v[i][2];
}
//按相反顺序在第0列上排序
排序(v.begin(),v.end(),comp);
排序(b.开始(),b.结束());
int ans=0;
对于(int i=0;iv[j][2])
ans+=1;
j++;
}
而(i
此解决方案使用段树,从而解决了中的问题 时间O(n*log(n))和空间O(n)


这种方法在Primusa接受的答案中得到了解释。

首先让我们假设我们的输入是以元组列表的形式出现的
T=[(a[0],B[0],C[0]),(a[1],B[1],C[1])…(a[N-1],B[N-1],C[N-1])

我们可以做的第一个观察是,我们可以按
T[0]
进行排序(顺序相反)。然后对于每个元组
(a,b,c)
,为了确定它是否不能赢,我们询问是否已经看到一个元组
(d,e,f)
,这样
e>b和&f>c
。我们不需要检查第一个元素,因为我们得到了
d>a
*,因为
t
是反向排序的

好的,那么现在我们如何检查第二个标准呢

我们可以这样重新构造它:在所有元组
(d,e,f)
,我们已经看到了
e>b
,那么
f
的最大值是多少?如果最大值大于
c
,则我们知道此元组无法获胜

为了处理这一部分,我们可以使用具有最大更新和最大范围查询的段树。当我们遇到一个元组
(d,e,f)
,我们可以设置
树[e]=max(树[e],f)
<代码>树[i]
将表示第三个元素,
i
是第二个元素

为了回答类似“f的最大值是多少,以致于b的最大值是多少”这样的问题,我们做了
max(tree[b+1…])
,以获得一系列可能的第二个元素中最大的第三个元素

因为我们只做后缀查询,所以可以使用修改过的fenwick树,但使用段树更容易解释

这将为我们提供一个
O(NlogN)
解决方案,用于排序
T
,并使用每个元组的段树执行
O(logN)


*注意:这实际上应该是
d>=a
。然而,当我们假设所有事物都是唯一的时,解释算法就更容易了。为了适应第一个元素的重复值,您需要做的唯一修改是在相同值的元组桶中处理查询和更新。这意味着我们将对具有相同第一个元素的所有元组执行检查,只有在这之后,我们才会对所有执行检查的元组更新
tree[e]=max(tree[e],f)
。这可以确保当另一个元组查询树时,没有具有相同第一个值的元组已经更新了树。

谢谢。我将使用分段树方法用解决方案代码更新这个问题。这是一个出色的解决方案。我一直在考虑分段树的方法,但你们在这里如此轻松地进行了布局,令人印象深刻!你能推荐一些好的资源来学习和练习段树上的问题吗?@Serialazer sure:是一个非常高质量的资源,底部有大量的练习问题,此外,一旦你完成了cp算法,这是一个非常好的实现它们的方法。一组能够获胜的玩家被称为“帕累托前线”或“帕累托前沿”。搜索这些术语将发现算法的其他讨论,例如。