题解:CF2062E1 The Game (Easy Version)

首先 \(a_{i}\le n\)

假设我们第一次选择了全局第二大的值 \(y\) (可能有多个相同的 \(y\)),删除掉整个子树

  1. 如果子树外面含有比 \(y\) 大的值 \(x\),那么我们第一个人选择 \(y\)。第二个人选择 \(x\) 后,没有再能选择的更大的数字了。所以第一个人获胜。

  2. 所有值为\(x\)的数字都在子树 \(y\) 里面,那么第一个人选择\(y\), 第二个人就会获胜。那么我们要找全局第三(四、五、六以此类推)大的值 \(z\) ,并重复执行 \(1\)\(2\) 操作。

由于是从大到小的,所以对于当前情况,只要子树外面有比现在大的值,第一个人选择了 \(x\),第二个人选择 \(y\)\(y > x\),那么第一个人一定没有能选的数了。

所有数字从大到小遍历一遍,发现子树外都没有比自己大的值,说明无解,输出 \(0\)

\(val[x]\) 是值大于等于 \(x\) 的数字个数。

\(dfn[x]\) 是搜索顺序,一整棵子树的dfn序时连续的, 记录子树大小 \(siz\) 可以计算。

查找这棵子树中有多少个大于 \(w\) 的值,可以用可持久化线段树来维护。可持久化线段树模板题

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 400005;
int n, a[N], val[N], siz[N], dfn[N], tot = 0, rt[N], fdfn[N], cnt = 0;
vector<int> g[N]; 
struct segement_tree
{
    int l, r, sm;
}tr[N * 20];
struct node
{
    int w, pos;
}d[N];
void dfs(int x, int fa)
{
    dfn[x] = ++ tot, siz[x] = 1;
    fdfn[tot] = x;
    for (int i = 0; i < g[x].size(); ++ i)
    {
        int y = g[x][i];
        if(y == fa) continue;
        dfs(y, x);
        siz[x] += siz[y];
    }
    return ;
}

void push_up(int p)
{
    tr[p].sm = tr[tr[p].l].sm + tr[tr[p].r].sm;
    return ;
}

int update(int u, int l, int r, int x)
{
    int p = ++ cnt;
    tr[p] = tr[u];
    if(l == r)
    {
        tr[p].sm += 1;
        return p;
    }
    int mid = l + r >> 1;
    if(x <= mid) tr[p].l = update(tr[u].l, l, mid, x);
    else tr[p].r = update(tr[u].r, mid + 1, r, x);
    push_up(p);
    return p;
}

int query(int u, int v, int l, int r, int L, int R)
{
    if(l > R || r < L) return 0;
    if(L <= l && r <= R) return tr[v].sm - tr[u].sm;
    int mid = l + r >> 1;
    return query(tr[u].l, tr[v].l, l, mid, L, R) + query(tr[u].r, tr[v].r, mid + 1, r, L, R);
}
bool cmp(node a, node b)
{
    return a.w > b.w;
}
int main()
{
    int T;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; ++ i) val[i] = 0, g[i].clear();
        cnt = 0, tot = 0;
        for (int i = 1; i <= n; ++ i) 
        {
            scanf("%d", &a[i]);
            d[i].w = a[i], d[i].pos = i;
            val[a[i]] ++;
        }
        sort(d + 1, d + n + 1, cmp);
        val[n + 1] = 0;
        for (int i = n - 1; i >= 1; -- i) val[i] += val[i + 1];
        for (int i = 1; i <= n - 1; ++ i)
        {
            int u, v;
            scanf("%d %d", &u, &v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        dfs(1, 0);
        for (int i = 1; i <= n; ++ i)
        {
            rt[i] = update(rt[i - 1], 1, n, a[fdfn[i]]);
        }
        bool pd = false;
        for (int i = 1; i <= n; ++ i)
        {
            int x = query(rt[dfn[d[i].pos] - 1], rt[dfn[d[i].pos] + siz[d[i].pos] - 1], 1, n, a[d[i].pos] + 1, n);
            if(x == val[a[d[i].pos] + 1]) 
            {
                continue;
            }
            else 
            {
                printf("%d\n", d[i].pos);
                pd = true;
                break;
            }
        }
        if(!pd)
        {
            printf("0\n");
        }
        for (int i = 1; i <= cnt; ++ i) tr[i].l = tr[i].r = tr[i].sm = 0;
    }
    return 0;
}
posted @ 2025-02-13 10:28  Helioca  阅读(84)  评论(0)    收藏  举报
Document