• 2019.10.6模拟赛


    T1 动物园

    题意

    给定一个带点权图,求每两个点之间路径上最小点权的最大值之和。

    怎么做

    点权下方边权跑最大生成树(边权是两个点中的最小值),这样就可以保证每条路径都是两个点之间最小点权的最大值。
    考虑统计答案,这个路径对答案的贡献是两边经过他的点的个数 * 2。在跑最小生成树的时候使用带权并查集维护两边点的数量即可。

    //优化了一下,跑的更快了
    #include <cstdio>
    #include <algorithm>
    #include <cctype>
    namespace fdata
    {
    inline char nextchar()
    {
        static const int BS = 1 << 21;
        static char buf[BS], *st, *ed;
        if (st == ed)
            ed = buf + fread(st = buf, 1, BS, stdin);
        return st == ed ? -1 : *st++;
    }
    #ifdef lky233
    #define nextchar getchar
    #endif
    template <typename Y>
    inline void poread(Y &ret)
    {
        ret = 0;
        char ch;
        while (!isdigit(ch = nextchar()))
            ;
        do
            ret = ret * 10 + ch - '0';
        while (isdigit(ch = nextchar()));
    }
    #undef nextcar
    } // namespace fdata
    using fdata::poread;
    using namespace std;
    const int MAXN = 1e5 + 10;
    const int MAXM = 1e6 + 10;
    int n, m;
    long long ans = 0;
    int val[MAXN];
    int a[MAXN], siz[MAXN];
    int find(int x) { return a[x] == x ? x : a[x] = find(a[x]); }
    struct road
    {
        int x, y, w;
        inline bool operator<(const road &t) const { return w > t.w; }
    } r[MAXM];
    int main()
    {
        poread(n), poread(m);
        for (register int *i = a; i <= a + n; ++i)
            *i = i - a;
        for (register int *i = siz; i <= siz + n; ++i)
            *i = 1;
        for (register int i = 1; i <= n; ++i)
            poread(val[i]);
        for (register int i = 1; i <= m; ++i)
        {
            poread(r[i].x), poread(r[i].y);
            r[i].w = min(val[r[i].x], val[r[i].y]);
        }
        sort(r + 1, r + m + 1);
        for (register int i = 1, cnt = 0; i <= m; ++i)
        {
            register int x = find(r[i].x);
            register int y = find(r[i].y);
            if (x == y)
                continue;
            ++cnt;
            ans += (long long)siz[x] * siz[y] * r[i].w * 2;
            a[x] = y;
            siz[y] += siz[x];
            if (cnt == n - 1)
                break;
        }
        printf("%lld
    ", ans);
    }
    

    T2 线段计数

    题意

    插入或删除线段,询问插入的线段覆盖了几个线段。线段长度递增

    怎么做

    我们考虑线段完全覆盖某一个线段的情况:

    R >= r && l >= L
    这样我们开两个树状数组维护区间左端点个数以及区间右端点个数。每次查询时答案就是 右端点左侧的右端点个数 减去 左端点左侧的左端点个数。
    这个方法会在下面这个情况出锅:

    但由于数据保证了线段长度单调递增,这个情况不存在啦啦啦。

    建议:贪婪大陆
    我竟然当时写的线段树

    //多测不清空,爆零两行泪
    #include <bits/stdc++.h>
    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #pragma GCC optimize("Ofast")
    #pragma GCC target("avx2")
    namespace fdata
    {
    inline char nextchar()
    {
        static const int BS = 1 << 21;
        static char buf[BS], *st, *ed;
        if (st == ed)
            ed = buf + fread(st = buf, 1, BS, stdin);
        return st == ed ? -1 : *st++;
    }
    #ifdef lky233
    #define nextchar getchar
    #endif
    template <typename Y>
    inline void poread(Y &res)
    {
        res = 0;
        bool bo = 0;
        char c;
        while (((c = nextchar()) < '0' || c > '9') && c != '-')
            ;
        if (c == '-')
            bo = 1;
        else
            res = c - 48;
        while ((c = nextchar()) >= '0' && c <= '9')
            res = (res << 3) + (res << 1) + (c - 48);
        if (bo)
            res = ~res + 1;
        // std::cerr << res << std::endl;
    }
    #undef nextcar
    } // namespace fdata
    using fdata::poread;
    using namespace std;
    namespace lky
    {
    const int MAXN = 2e5 + 10;
    int n, m, tot;
    //封装是个好东西
    class T
    {
    public:
        int t[MAXN << 1];
        inline void init() { memset(t, 0, sizeof(t)); }
        inline void add(int x)
        {
            for (; x <= m; x += (x & -x))
                ++t[x];
        }
        inline void del(int x)
        {
            for (; x <= m; x += (x & -x))
                --t[x];
        }
        inline int ask(int x)
        {
            register int res = 0;
            for (; x; x -= (x & -x))
                res += t[x];
            return res;
        }
    } t1, t2;
    struct node
    {
        int opt, x, y;
    } opt[MAXN];
    //根本不用开两个结构体分别记录操作和序列,只要这样映射一下
    int po[MAXN];
    int b[MAXN << 1];
    inline int find(const int &x)
    {
        register int l = 1, r = m, res = 1, mid;
        while (l <= r)
        {
            mid = (l + r) >> 1;
            if (b[mid] <= x)
                res = mid, l = mid + 1;
            else
                r = mid - 1;
        }
        return res;
    }
    inline void sov()
    {
        poread(n);
        t1.init(), t2.init();
        tot = 0;
        m = 0;
        for (register int i = 1, cnt = 0; i <= n; ++i)
        {
            poread(opt[i].opt), poread(opt[i].x);
            if (opt[i].opt == 0)
            {
                opt[i].y = opt[i].x + (++tot);
                po[tot] = i;
                b[++m] = opt[i].x, b[++m] = opt[i].y;
            }
        }
        sort(b + 1, b + m + 1);
        m = unique(b + 1, b + m + 1) - (b + 1);
        for (register int i = 1; i <= n; ++i)
        {
            if(opt[i].opt == 1)
                continue;
            opt[i].x = find(opt[i].x);
            opt[i].y = find(opt[i].y);
        }
        for (register int i = 1, cnt = 0; i <= n; ++i)
        {
            if (opt[i].opt == 0)
            {
                ++cnt;
                printf("%lld
    ", t2.ask(opt[po[cnt]].y) - t1.ask(opt[po[cnt]].x - 1));
                t1.add(opt[po[cnt]].x), t2.add(opt[po[cnt]].y);
            }
            else
            {
                t1.del(opt[po[opt[i].x]].x), t2.del(opt[po[opt[i].x]].y);
            }
        }
    }
    } // namespace lky
    signed main()
    {
    #ifdef lky233
        freopen("testdata.in", "r", stdin);
        freopen("testdata.out", "w", stdout);
    #endif
        int T;
        poread(T);
        for (register int ttt = 1; ttt <= T; ++ttt)
        {
            printf("Case #%d:
    ", ttt);
            lky::sov();
        }
    }
    

    T3 填数游戏

    题意

    给一个矩阵,每个格子可以填1或者-1,会给定一些已经填了的格子。问可能填法。

    咋做

    打表找规律(雾)
    如果行列相加是偶数,没有可行解
    否则判断给出的状态是否合法
    合法的话答案就是({2 ^ {(剩余格子 - 1)}})

    //之前那个太假,被hack,这个快多了
    #include <bits/stdc++.h>
    namespace fdata
    {
    inline char nextchar()
    {
        static const int BS = 1 << 21;
        static char buf[BS], *st, *ed;
        if (st == ed)
            ed = buf + fread(st = buf, 1, BS, stdin);
        return st == ed ? -1 : *st++;
    }
    #ifdef lky233
    #define nextchar getchar
    #endif
    template <typename Y>
    inline void poread(Y &res)
    {
        res = 0;
        bool bo = 0;
        char c;
        while (((c = nextchar()) < '0' || c > '9') && c != '-')
            ;
        if (c == '-')
            bo = 1;
        else
            res = c - 48;
        while ((c = nextchar()) >= '0' && c <= '9')
            res = (res << 3) + (res << 1) + (c - 48);
        res = bo ? ~res + 1 : res;
    }
    #undef nextcar
    } // namespace fdata
    using fdata::poread;
    using namespace std;
    int MOD;
    int n, m;
    int k;
    int cx[1000005], cy[1000005];
    unsigned char nx[1000005], ny[1000005];
    inline int qpow(int a, long long b)
    {
        if (b <= 0)
            return 1;
        int res = 1;
        for (; b; b >>= 1)
        {
            if (b & 1)
                res = 1ll * res * a % MOD;
            a = 1ll * a * a % MOD;
        }
        return res;
    }
    signed main()
    {
        poread(n), poread(m), poread(k);
        if ((n + m) & 1)
        {
            puts("0");
            return 0;
        }
        for (register int i = 1, x, y, num; i <= k; ++i)
        {
            poread(x), poread(y), poread(num);
            ++cx[x], ++cy[y];
            nx[x] ^= (num == -1);
            ny[y] ^= (num == -1);
            if (cx[x] == m)
            {
                if (!nx[x])
                {
                    puts("0");
                    return 0;
                }
                else
                    --k;
            }
            if (cy[y] == n)
            {
                if (!ny[y])
                {
                    puts("0");
                    return 0;
                }
                else
                    --k;
            }
        }
        poread(MOD);
        cout << qpow(2, 1ll * (n - 1) * (m - 1) - k) << endl;
    }
    
    
  • 相关阅读:
    Oracle导出txt文本文件
    oracle spool
    [Oracle, MySQL] Oracle通过dblink连接MySQL
    正则表达式速查表
    常用的正则表达式
    python3 打印九九乘法口诀表
    canda 常用命令
    python3 拼接字符串的7种方法
    Python 字符串格式化输出方式
    PyCharm 解决有些库(函数)没有代码提示
  • 原文地址:https://www.cnblogs.com/Shiina-Rikka/p/11629482.html
Copyright © 2020-2023  润新知