牛客练习赛2

牛客练习赛2

A

n支队伍一共参加了三场比赛。

一支队伍x认为自己比另一支队伍y强当且仅当x在至少一场比赛中比y的排名高。

求有多少组(x,y),使得x自己觉得比y强,y自己也觉得比x强。

(x, y), (y, x)算一组。

题解:

也就是找多少对 \(x < x1, y < y1 , z > z1\) 或者 \(x < x1, y > y1, z < z1\) …………等

也就是总共的方案数减去 \(x < x1, y < y1, z < z1\)的。

这个不就是三维偏序吗?

第一维排序排序, 第二维分治, 第三维用数组数组

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 7;
struct node {
    int a, b, c;
}p[N];

int sum[N], n;

int lowbit(int x) {
    return x & (-x);
}

void add(int pos, int v) {
    while (pos <= n) {
        sum[pos] += v;
        pos += lowbit(pos); 
    }
}

int query(int l, int r) {
    int res = 0;
    while (r > 0) {
        res += sum[r];
        r -= lowbit(r);
    }
    l--;
    while (l > 0) {
        res -= sum[l];
        l -= lowbit(l);
    }
    return res;
}



bool cmp(node x, node y) {
    return x.a < y.a;
}

struct data {
    int f, a, b, c;
};

bool cmp1(data x, data y) {
    if (x.b == y.b) {
        return x.f < y.f;
    }
    return x.b < y.b;
}

vector<data> g;

#define m (l + r) / 2

ll ans = 0;

void CDQ(int l, int r) {
    if (l == r) return;
    g.clear();
    for (int i = l; i <= m; i++) {
        g.push_back({0, p[i].a, p[i].b, p[i].c});
    }

    for (int i = m + 1; i <= r; i++) {
        g.push_back({1, p[i].a, p[i].b, p[i].c});
    }

    sort(g.begin(), g.end(), cmp1);
    for (int i = 0; i < g.size(); i++) {
        if (g[i].f == 0) {
            add(g[i].c, 1);
        } else {
            ans += query(1, g[i].c);
        }
    }

    for (int i = 0; i < g.size(); i++) {
        if (g[i].f == 0) {
            add(g[i].c, -1);
        }
    }

    CDQ(l, m);
    CDQ(m + 1, r);
   
}

int main() {

    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d %d %d", &p[i].a, &p[i].b, &p[i].c);
    }
    sort(p + 1, p + n + 1, cmp);
    CDQ(1, n);
    n--;
    cout << 1ll*(1ll*(n + 1) * 1ll*n /  2) - ans << endl;


}

c

树国是一个有n个城市的国家,城市编号为1∼n。连接这些城市的道路网络形如一棵树,

即任意两个城市之间有恰好一条路径。城市中有k个帮派,编号为1∼k。每个帮派会占据一些城市,以进行非法交易。有时帮派之间会结盟,这就使得城市更加不安全了。同一座城市中可能有多个帮派。

当一些帮派结成联盟时,他们会更加强大,同时也更加危险。他们所控制的城市数会显著增加。具体地,一个联盟控制的城市是联盟中所有帮派所占据的城市,再加上这些城市两两之间路径上的所有城市。

shy是树国的市长,他想要选择一个城市作为首都。在决定之前,他要先做一些调研。为此,他找来你帮他回答一些询问,你能做到吗?在每个询问中,shy会选择一个城市作为首都,同时会告诉你当前活跃的帮派的集合。在这个询问中,你只需要考虑给定的集合中的帮派,其他的帮派你可以当作不存在。已知给定集合中的这些帮派结成了联盟,shy希望抓获联盟中的人,以得到关于整个联盟的一些信息。为此,他要找到被联盟控制的所有城市中离首都最近的一座城市到首都的距离。有可能首都本身就被控制了,此时答案为0。请注意,询问之间相互独立,互不影响。

题解:

要注意, 帮派结盟时控制, 联盟中所有帮派所占据的城市,再加上这些城市两两之间路径上的所有城市

要分为两种情况, 第一中就是, 选择的点在不在帮派控制的子树上, 那么直接算, 这个点所有所有点的lca距离

, 否则二分查找dfs序。

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 7;

int head[N], n, m, q, top = 1, fn[N][30], deep[N];
int dfn[N], id[N];

struct edge{
    int to, nxt;
}e[2 * N];

void add_edge(int u, int v) {
    e[top].to = v;
    e[top].nxt = head[u];
    head[u] = top++;
}

int o = 1;

void dfs(int u, int fa) {
    fn[u][0] = fa;
    deep[u] = deep[fa] + 1;
    dfn[u] = o++;
    id[o - 1] = u;
    for (int i = 1; i <= 20; i++) {
        fn[u][i] = fn[fn[u][i - 1]][i - 1];
    }

    for (int i = head[u]; i; i = e[i].nxt) {
        int to = e[i].to;
        if (to == fa) continue;
        dfs(to, u);
    }
}

int get_lca(int x, int y) {
    if (deep[y] > deep[x]) {
        swap(x, y);
    }
    int d = deep[x] - deep[y];
    int cnt = 0;
    while (d) {
        if (d & 1) {
            x = fn[x][cnt];
        }
        cnt++;
        d = d / 2;
    }

    if (x == y) return x;

    for (int i = 20; i >= 0; i--) {
        if (fn[x][i] != fn[y][i]) {
            x = fn[x][i];
            y = fn[y][i];
        }
    }
    return fn[x][0];
}


vector<int> g[N];

int lca[N], cat[N];

int get_dist(int x, int y, int lc) {

    return deep[x] + deep[y] - 2 * deep[lc];

}


int main() {
    scanf("%d", &n);
    for (int i = 1; i < n; i++) {
        int u, v;
        scanf("%d %d", &u, &v);
        add_edge(u, v);
        add_edge(v, u);
    }
    dfs(1, 0);
    scanf("%d", &m);
    for (int i = 1; i <= m; i++) {
        int c; scanf("%d", &c);
        for (int j = 1; j <= c; j++) {
            int x; scanf("%d", &x);
            if (j == 1) {
                lca[i] = x;
            } else {
                lca[i] = get_lca(lca[i], x);
            }
            g[i].push_back(dfn[x]);
        }
        sort(g[i].begin(), g[i].end());
    }
    

    scanf("%d", &q);
    while (q--) {
        int u, x; scanf("%d %d", &u, &x);
        int LCA;
        for (int i = 1; i <= x; i++) {
            scanf("%d", &cat[i]);
            if (i == 1) {
                LCA = lca[cat[i]];
            } else {
                LCA = get_lca(LCA, lca[cat[i]]);
            }
        }

        int LC = get_lca(LCA, u);
        int ans = INT_MAX;
        if (LC != LCA) {
            printf("%d\n", get_dist(u, LCA, LC));
        } else {

            for (int i = 1; i <= x; i++) {
                int p = lower_bound(g[cat[i]].begin(), g[cat[i]].end(), dfn[u]) - g[cat[i]].begin();

                if (p == g[cat[i]].size()) {
                    p--;
                    LC = get_lca(u, id[g[cat[i]][p]]);
                    ans = min(ans, get_dist(u, LC, LC));
                }  else {
         
                    LC = get_lca(u, id[g[cat[i]][p]]);
                    ans = min(ans, get_dist(u, LC, LC));
                    if (p) {
                        p--;
                        LC = get_lca(u, id[g[cat[i]][p]]);
                        ans = min(ans, get_dist(u, LC, LC));
                    }
                
                }

               
            }
            printf("%d\n", ans);

        }


    }

}
posted @ 2020-11-10 11:53  ccsu_zhaobo  阅读(89)  评论(0编辑  收藏  举报