zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    26 转义符 re模块 方法 random模块 collection模块的Counter方法
    25 正则表达式
    24 from 模块 import 名字
    24 from 模块 import 名字
    24 from 模块 import 名字
    23 析构方法 items系列 hash方法 eq方法
    21 isinstance issubclass 反射 _str_ _new_ _len_ _call_
    20 属性, 类方法, 静态方法. python2与python3的区别.
    python(1)
    python之字符串格式化
  • 原文地址:https://www.cnblogs.com/Shiina-Rikka/p/11629482.html
Copyright © 2011-2022 走看看