8.23 模拟赛

版权声明:_ https://blog.csdn.net/lunch__/article/details/81982960

今天题目又爆零啊, N O I P 遇到这种毒瘤题我这种菜鸡 O I e r 注定退役了

T1

这里写图片描述

这个题目很容易发现链的答案就是 1

假如不是链的话,那么至少存在一个度数大于 2 的点

如果我们把这个点作为根,那么每个点断开后通往其祖先的联通块内一定存在一个黑点,这样子我们对于每个点只用考虑它的子树了,记 f [ u ] u 子树内的黑点数,那么 f [ u ] = f a [ v ] == u f [ v ] ,如果有 x 个子树内还没有点的话,那么对 x 1 个子树内放点就好了,因为向祖先的那个联通块一定是联通的…

这种辣鸡 d p 都没想出来我是真的菜

Codes

#include<bits/stdc++.h>

#define pb push_back

using namespace std;

const int N = 1e5 + 10;
vector<int> G[N];
int f[N], de[N];
int n, root, ans;

void dfs(int u, int fa) {
    int sum = 0;
    for(auto v : G[u])
        if(v != fa) {
            dfs(v, u);
            f[u] += f[v];
            if(!f[v]) ++ sum;
        }
    if(sum) f[u] += sum - 1;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("bf.in", "r", stdin);
    freopen("bf.out", "w", stdout);
#endif
    int x, y;
    scanf("%d", &n);
    for(int i = 1; i < n; ++ i) {
        scanf("%d%d", &x, &y);
        G[x].pb(y), G[y].pb(x);
        ++ de[x], ++ de[y];
        if(de[x] > de[root]) root = x;
        if(de[y] > de[root]) root = y;
    }
    if(de[root] <= 2) return printf("1"), 0;
    dfs(root, -1);
    printf("%d\n", f[root]);
    return 0;
}

T2

戳我啊 o v o

T3

这里写图片描述

这道题好像数据不是很强…?,我三个 l o g 的做法都不是最慢的

如果一条路径完全覆盖另一条,那么另一条的两个端点一定都在这条路径上

对这棵树做下树链剖分,然后重链的 d f s 序就是连续的了,对于每一条路径 [ x , y ] ,把对于一个端点开一个 v e c t o r 把另一个端点放在上面。

主席树上维护的是每个 d f s 序的出现的次数

每次在其父亲的基础上开新的版本

但是查询我不知道怎么 O ( l o g 2 n ) 搞,于是我把重链都存下来了..
每次 O ( l o g 2 n ) 枚举两条重链 再用主席树查询就好了..

时间复杂度 O ( n l o g 3 n )

Codes

#include<bits/stdc++.h>

#define pb push_back
#define ll long long

using namespace std;

int read() {
    int _ = 0, ___ = 1; char __ = getchar();
    for(; !isdigit(__); __ = getchar()) if(__ == '-') ___ = -1;
    for(; isdigit(__); __ = getchar()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
    return _ * ___;
}

const int N = 2e5 + 10;
vector<int> G[N], D[N];
int n, m, root[N];
int X[N], Y[N];

struct Chairman_Tree {
#define ls(x) (T[x].ch[0])
#define rs(x) (T[x].ch[1])
#define mid ((l + r) >> 1)
    int cnt;
    struct node {
        int ch[2], sum; 
    }T[N * 70];

    void update(int &x, int pre, int l, int r, int p) {
        T[x = ++ cnt] = T[pre]; ++ T[x].sum;
        if(l != r) {
            if(p <= mid) update(ls(x), ls(pre), l, mid, p);
            else update(rs(x), rs(pre), mid + 1, r, p);
        }
    }

    int query(int x, int pre, int l, int r, int L, int R) {
        int res = 0;
        if(L <= l && r <= R)
            res = T[x].sum - T[pre].sum;
        else {
            if(L <= mid) res += query(ls(x), ls(pre), l, mid, L, R);
            if(R > mid) res += query(rs(x), rs(pre), mid + 1, r, L, R);
        }
        return res;
    }

}T;

void add(int x, int y) {
    G[x].pb(y), G[y].pb(x);
}

int dep[N], fa[N], id[N], size[N];
int heavy[N], top[N], cnt;
int sumx[N], sumy[N];

void dfs1(int x) {
    size[x] = 1;
    for(auto v : G[x])
        if(!dep[v]) {
            dep[v] = dep[x] + 1;
            fa[v] = x;
            dfs1(v);
            size[x] += size[v];
            if(size[v] > size[heavy[x]])
                heavy[x] = v;
        }
}

void dfs2(int x, int ancestor) {
    id[x] = ++ cnt; top[x] = ancestor;
    if(heavy[x]) dfs2(heavy[x], ancestor);
    for(auto v : G[x]) 
        if(v != fa[x] && v != heavy[x])
            dfs2(v, v);
}

void dfs3(int x) {
    root[x] = root[fa[x]];
    for(auto v : D[x]) 
        T.update(root[x], root[x], 1, n, id[v]);
    for(auto v : G[x])
        if(v != fa[x])
            dfs3(v);
}

void Init() {
    read(), n = read(), m = read();
    for(int i = 1; i < n; ++ i)
        add(read(), read());
    for(int i = 1; i <= m; ++ i) {
        X[i] = read(), Y[i] = read();
        D[X[i]].pb(Y[i]);
    }
    dfs1(dep[1] = 1); dfs2(1, 1); dfs3(1);
}

int cal(int x, int y) {
    ll res = 0; sumx[0] = sumy[0] = 0;
    while(top[x] != top[y]) {
        if(dep[top[x]] < dep[top[y]])
            swap(x, y);
        sumx[++ sumx[0]] = top[x];
        sumy[++ sumy[0]] = x;
        x = fa[top[x]];
    }
    if(dep[x] > dep[y]) 
        swap(x, y);
    sumx[++ sumx[0]] = x; 
    sumy[++ sumy[0]] = y;
    for(int i = 1; i <= sumx[0]; ++ i)
        for(int j = 1; j <= sumy[0]; ++ j)
            res += T.query(root[sumy[i]], root[fa[sumx[i]]], 1, n, id[sumx[j]], id[sumy[j]]);
    return res;
}

void Solve() {
    int res = 0;
    for(int i = 1; i <= m; ++ i) 
        res += cal(X[i], Y[i]);
    ll x = res - m, y = 1ll * m * (m - 1) / 2;
//  cout << x << ' ' << y << endl;
    ll gcd = __gcd(x, y);
    printf("%lld/%lld", x / gcd, y / gcd);
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("std.in", "r", stdin);
    freopen("std.out", "w", stdout);
#endif
    Init();
    Solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/81982960