zoukankan      html  css  js  c++  java
  • 9.21模拟赛解题报告

    题目及数据:

    https://www.lanzous.com/i1xdr8h

    心路历程

    预计分数:$100+ 100 +60 = 260$

    实际得分:$100 + 100 + 0 = 200$

    我这次检查了三遍绝对没算错!!!

    上来看T1,咦?我好像做过这题在仙人掌上的版本。。树上更简单吧。。写+拍 1h,期间拍出了暴力的两个bug。。。

    看T2,好难啊,不会做啊 qwq。。然后开始强行套算法。恩。把单调队列套进去发现是可行的。。而且好像还可以无视题目的一些性质。。嘿嘿嘿这题有加强版了

    T3更神仙。。想了一个并查集优化暴力的$n^2$算法,然后写挂了。。。自己造的输出跑的贼快,一上评测机就死循环。。

    因为昨天晚上打cf特别困,而且自我感觉$260$应该不低了,就睡了一个半小时。。。。。。。。。

    T1

    听大佬们说是原题啊Orz

    我居然不知道 我好像是做过然后忘的一干二净。。

    很显然,把路径拆开,判断lca之间的关系即可

    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<vector>
    #include<cstring>
    #define getchar() ((p1 == p2) && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
    using namespace std;
    const int MAXN = 1e5 + 10;
    char buf[(1 << 21)], *p1 = buf, *p2 = buf;
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int T, N, Q, fa[MAXN], dep[MAXN], top[MAXN], son[MAXN], siz[MAXN];
    vector<int> v[MAXN];
    void init() {
        for(int i = 1; i <= N; i++) v[i].clear();
        memset(top, 0, sizeof(top));
        memset(son, 0, sizeof(son));
    }
    void dfs1(int x, int _fa) {
        siz[x] = 1; fa[x] = _fa;
        for(int i = 0; i < v[x].size(); i++) {
            int to = v[x][i];
            if(to == _fa) continue;
            dep[to] = dep[x] + 1;
            dfs1(to, x);
            siz[x] += siz[to];
            if(siz[to] > siz[son[x]]) son[x] = to;
        }
    }
    void dfs2(int x, int topf) {
        top[x] = topf;
        if(!son[x]) return ;
        dfs2(son[x], topf);
        for(int i = 0; i < v[x].size(); i++) {
            int to = v[x][i];
            if(top[to]) continue;
            dfs2(to, to);
        }
    }
    int LCA(int x, int y) {
        while(top[x] != top[y]) {
            if(dep[top[x]] < dep[top[y]]) swap(x, y);
            x = fa[top[x]];
        }
        if(dep[x] > dep[y]) swap(x, y);
        return x;
    }
    bool check(int a, int x, int y) {
        if(dep[x] < dep[y]) swap(x, y);
        if(LCA(a, x) == a && LCA(a, y) == y) return 1;
        else return 0;
    }
    int main() {
        freopen("railway.in", "r", stdin);
        freopen("railway.out", "w", stdout);
        T = read(); 
        while(T--) {
            N = read(); Q = read();
            init();
            for(int i = 1; i <= N - 1; i++) {
                int x = read(), y = read();
                v[x].push_back(y); v[y].push_back(x);
            }
            dep[1] = 1; dfs1(1, 0);
            dfs2(1, 1);
            while(Q--) {
                int xx1 = read(), yy1 = read(), xx2 = read(), yy2 = read();
                int lca1 = LCA(xx1, yy1), lca2 = LCA(xx2, yy2);
                if(check(lca1, xx2, lca2) || check(lca1, yy2, lca2) || check(lca2, xx1, lca1) || check(lca2, yy1, lca1)) puts("YES");
                else puts("NO");
            }
        }
        return 0;
    }
    T1

    T2

    式子化简完了之后应该是求

    $$sum_{i = 1}^n sum_{j = 1}^i mx - mn$$

    其中

    $mx = max(a[j], a[j+1], dots a[i])$

    $mn = min(a[j], a[j+1], dots a[i])$

    单调栈维护即可。。。。

    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<iostream>
    #define LL long long 
    using namespace std;
    const LL MAXN = 1e5 + 10;
    inline LL read() {
        char c = getchar(); LL x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    LL T, N;
    LL a[MAXN], q[MAXN];
    LL solve() {
        LL h = 1, t = 0, ans = 0, sum = 0;
        for(LL i = 1; i <= N; i++) {
            while(h <= t && a[i] > a[q[t]]) sum -= a[q[t]] * (q[t] - q[t - 1]), t--;
            q[++t] = i;
            ans += a[i] * (q[t] - q[t - 1]) + sum;
            sum += a[i] * (q[t] - q[t - 1]);
        }
        return ans;
    }
    int main() {
        freopen("count.in", "r", stdin);
        freopen("count.out", "w", stdout);
        T = read();
        while(T--) {
            N = read();
            for(LL i = 1; i <= N; i++) a[i] = read();
            LL ans = solve();
            for(LL i = 1; i <= N; i++) a[i] = -a[i];
            LL ans2 = solve();
            cout << ans + ans2 << endl;
        }
        return 0;
    }
    T2

    T3

    不明白出这种题有什么意义。。。

    dsu on tree, set,这都是noip知识点????

    而且标算好像就是在想尽各种方法优化暴力。。。

    考虑直接算一条边的贡献

    首先考虑暴力怎么算

    对于一条边来说,如果子树内有连续的区间,比如$[1, 2, 3, 4]$那么在统计他们的答案时显然不会经过该边,他们对答案的贡献为$frac{n(n -1)}{2} $

    用总贡献减去即可。

    然后可以分成子树内和子树外讨论,子树内用并查集维护,子树外用set维护并查集的补集

    做完了。。。

    代码里面的solve函数是抄的标算,,,实在写不出来啊qwq

    #include<bits/stdc++.h>
    #define LL long long 
    using namespace std;
    const int MAXN = 1e5 + 10;
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int N, dep[MAXN], siz[MAXN], son[MAXN], dsu[MAXN], Son, vis[MAXN], ds[MAXN];
    vector<int> v[MAXN];
    set<int> s;
    LL AnsOut, AnsIn, ans;
    void dfs(int x, int _fa) {
        siz[x] = 1;
        for(int i = 0; i < v[x].size(); i++) {
            int to = v[x][i]; if(to == _fa) continue;
            dfs(to, x);
            siz[x] += siz[to];
            if(siz[to] > siz[son[x]]) son[x] = to;
        }
    }
    LL calc(LL x) {
        return x * (x - 1) / 2;
    }
    void Clear() {
        s.clear(); AnsOut = calc(N); AnsIn = 0;
        s.insert(0); s.insert(N + 1);
    }
    int find(int x) {
        return dsu[x] == x ? dsu[x] : dsu[x] = find(dsu[x]);
    }
    void solve(int x) {
        s.insert(x);
        set<int>::iterator s1, s2, it;
        s1 = s2 = it = s.find(x);
        s1--; s2++;
        AnsOut -= calc((*s2) - (*s1) - 1);
        AnsOut += calc((*s2) - (*it) - 1) + calc((*it) - (*s1) - 1);
        vis[x] = 1;
        if(vis[x - 1]) {
            int fx = find(x - 1), fy = find(x);
            AnsIn += ds[fx] * ds[fy];
            dsu[fx] = fy;
            ds[fy] += ds[fx];
        }
        if(vis[x + 1]) {
            int fx = find(x + 1), fy = find(x);
            AnsIn += ds[fx] * ds[fy];
            dsu[fx] = fy;
            ds[fy] += ds[fx];
        }
    }
    void Add(int x, int fa) {
        solve(x);
        for(int i = 0; i < v[x].size(); i++) {
            int to = v[x][i];
            if(to == fa || to == Son) continue;
            Add(to, x);
        }
    }
    void Delet(int x, int fa) {
        vis[x] = 0; ds[x] = 1; dsu[x] = x;
        for(int i = 0; i < v[x].size(); i++) {
            int to = v[x][i];
            if(to == fa) continue;
            Delet(to, x);
        }
    } 
    void dfs2(int x, int fa, int opt) {
        for(int i = 0; i < v[x].size(); i++) {
            int to = v[x][i];
            if(to == fa || (to == son[x])) continue;
            dfs2(to, x, 0);
        }
        if(son[x]) dfs2(son[x], x, 1); Son = son[x];
        Add(x, fa);
        ans += calc(N) - AnsIn - AnsOut;
        if(opt == 0) Delet(x, fa), Clear(), Son = 0;
    }
    main() {
        N = read();
        for(int i = 1; i <= N - 1; i++) {
            int x = read(), y = read();
            v[x].push_back(y); v[y].push_back(x);
        }
        for(int i = 1; i <= N; i++) dsu[i] = i, ds[i] = 1;
        dep[1] = 1; dfs(1, 0);
        Clear(); 
        dfs2(1, 0, 0);
        cout << ans;
        return 0;
    }
    /*
    10
    1 9
    9 7
    9 5
    5 3
    9 4
    4 8
    1 10
    1 2
    3 6
    
    4
    1 4
    1 3
    2 4
    */
    T3
  • 相关阅读:
    bzoj4195 [Noi2015]程序自动分析
    bzoj4236 JOIOJI hash 模拟
    bzoj1012 [JSOI2008]最大数maxnumber
    day 4 名片管理系统 -函数版
    day 3 局部变量 全局变量
    day 2 函数的嵌套
    day1 函数 (独立功能代码块)
    day 14 元组
    day 13 字典dict 操作
    day 12 列表字典 补充
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/9687296.html
Copyright © 2011-2022 走看看