• 省选测试5


    A 序列

    题目大意 : 写一个程序,支持区间加,区间取max,单点询问值和修改过的次数(数值改变才算修改)

    • 挺裸的吉司机线段树,考试时写假了

    Code

    Show Code
    #include <cstdio>
    #include <algorithm>
    #define ls (rt << 1)
    #define rs (rt << 1 | 1)
    
    using namespace std;
    typedef long long ll;
    const int N = 1e5 + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar())
            if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar())
            x = x * 10 + c - '0';
        return x * f;
    }
    
    int n, a[N];
    
    struct Tree {
        ll m, s, ta; //m -> mininum, s -> second mininum, ta -> tag_add
        int na, nc; //na -> number of times to add, nc -> number of times to modifications
    }t[N*4];
    
    void Pushup(int rt) {
        if (t[ls].m == t[rs].m) t[rt].m = t[ls].m, t[rt].s = min(t[ls].s, t[rs].s);
        else if (t[ls].m < t[rs].m) t[rt].m = t[ls].m, t[rt].s = min(t[ls].s, t[rs].m);
        else t[rt].m = t[rs].m, t[rt].s = min(t[ls].m, t[rs].s);
    }
    
    void Build(int rt, int l, int r) {
        if (l == r) return t[rt] = (Tree) {a[l], (ll)1e15}, void();
        int mid = l + r >> 1;
        Build(ls, l, mid); Build(rs, mid+1, r);
        Pushup(rt);
    }
    
    void Update(int rt, ll w, int nc) {
        if (t[rt].m < w) t[rt].m = w, t[rt].nc += nc;
    }
    
    void Pushdown(int rt) {
        if (t[rt].na) {
            ll ta = t[rt].ta; int na = t[rt].na; t[rt].ta = t[rt].na = 0;
            t[ls].m += ta; t[ls].s += ta; t[ls].ta += ta; t[ls].na += na;
            t[rs].m += ta; t[rs].s += ta; t[rs].ta += ta; t[rs].na += na;
        }
        if (t[rt].nc) {
            ll m = t[rt].m; int nc = t[rt].nc; t[rt].nc = 0;
            if (t[ls].m < m) t[ls].m = m, t[ls].nc += nc;
            if (t[rs].m < m) t[rs].m = m, t[rs].nc += nc;
        }
    }
    
    void Add(int rt, int l, int r, int x, int y, int w) {
        if (x <= l && r <= y) return t[rt].m += w, t[rt].s += w, t[rt].ta += w, t[rt].na++, void();
        int mid = l + r >> 1; Pushdown(rt);
        if (x <= mid) Add(ls, l, mid, x, y, w);
        if (y > mid) Add(rs, mid+1, r, x, y, w);
        Pushup(rt);
    }
    
    void Change(int rt, int l, int r, int x, int y, int w) {
        if (w <= t[rt].m) return;
        if (x <= l && r <= y && w < t[rt].s) {
            if (t[rt].m < w) t[rt].m = w, t[rt].nc++;
            return;
        }
        int mid = l + r >> 1; Pushdown(rt);
        if (x <= mid) Change(ls, l, mid, x, y, w);
        if (y > mid) Change(rs, mid+1, r, x, y, w);
        Pushup(rt);
    }
    
    int Ask(int rt, int l, int r, int x) {
        if (l == r) return rt;
        int mid = l + r >> 1; Pushdown(rt);
        if (x <= mid) return Ask(ls, l, mid, x);
        else return Ask(rs, mid + 1, r, x);
    }
    
    int main() {
        n = read();
        for (int i = 1; i <= n; ++i) a[i] = read();
        Build(1, 1, n);
        for (int m = read(); m; --m) {
            char od; scanf(" %c", &od);
            if (od == 'A') {
                int l = read(), r = read(), w = read();
                if (w) Add(1, 1, n, l, r, w);
            }
            else if (od == 'M') {
                int l = read(), r = read();
                Change(1, 1, n, l, r, read());
            }
            else {
                int rt = Ask(1, 1, n, read());
                printf("%lld %d
    ", t[rt].m, t[rt].na + t[rt].nc);
            }
        }
        return 0;
    }
    

    B 旅行计划

    题目大意 :给定一个带权无向图,每次询问两点间路径权值和 mod K 的最小值,可重复经过点和边

    • 对于 K 为奇数的部分如果联通就直接大力 puts("0") 就好了,因为只要存在一条路径,来回一共走 K 次就一定可以把权值和 mod K 变成 0

    • 正解的话先算出这个联通块里所有边与 K 的 GCD g,当 k/g 是奇数的时候就来回走 k/g 次可以把答案变为 0

    • 如果 k/g 是偶数,两点间距离是偶数也一定可以构造出 0 的情况,证明一下,我们现在可以走任意边偶数次并回到原点,那么这部分的权值和就是 (sum _i 2x_id_i),现在所有的边和 K 都除掉他们的GCD后,由扩展裴蜀定理可知 (sum _i x_id_iequiv 1mod K) ,所以 (sum _i 2x_id_iequiv 2mod K),这样的话就一定可以构造出mod k值为2的路径, 走这种路径 ((k-x)mod k)/2 次就可以构造出0

    • 如果联通块里有奇环的话也可以构造出 0,原因是从起点经过奇环再回到起点再走奇数长度到终点,这样长度就是奇数+偶数+奇数=偶数,可以把这个当作偶数路径,然后就套用上一条的结论就能构造出0了

    • 如果上面的情况都没有的话那最小的可以构造出值为 g 的答案

    Code

    Show Code
    #include <cstdio>
    
    using namespace std;
    const int N = 1e5 + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar())
            if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar())
            x = x * 10 + c - '0';
        return x * f;
    }
    
    struct Edge {
        int n, t, d;
    }e[N*2];
    int h[N], edc;
    
    void Add(int x, int y, int z) {
        e[++edc] = (Edge) {h[x], y, z}; h[x] = edc;
    }
    
    bool v[N];
    int n, m, q, f[N], g[N], c[N]; 
    
    int Find(int x) {
        return x == f[x] ? x : f[x] = Find(f[x]);
    }
    
    int Gcd(int a, int b) {
        return b ? Gcd(b, a % b) : a;
    }
    
    void Dfs(int x, int col) {
        int f = Find(x); c[x] = col;
        for (int i = h[x]; i; i = e[i].n) {
            int y = e[i].t, d = e[i].d / g[f];
            if (!c[y]) Dfs(y, col ^ (d & 1));
            else if ((col ^ (d & 1)) != c[y]) v[f] = 1;
        }
    }
    
    int main() {
        n = read(); m = read(); q = read();
        for (int i = 1; i <= n; ++i) f[i] = i;
        while (m--) {
            int x = read(), y = read(), z = read();
            Add(x, y, z); Add(y, x, z);
            x = Find(x), y = Find(y);
            if (x == y) g[x] = Gcd(g[x], z);
            else f[y] = x, g[x] = Gcd(g[x], Gcd(g[y], z));
        }
        for (int i = 1; i <= n; ++i) 
            if (!c[i]) Dfs(i, 2);
        while (q--) {
            int x = read(), y = read(), k = read(); 
            int fx = Find(x), fy = Find(y), gcd = Gcd(k, g[fx]);
            if (fx != fy) puts("NIE");
            else if ((k / gcd) & 1 || c[x] == c[y] || v[fx]) puts("0");
            else printf("%d
    ", gcd);
        }
        return 0;
    }
    

    C Hack

    题目大意 : 一个带权有向图,删去一些边保证从0不能走到n-1,并且任意一条路径上不能有两条边被删

    • 如果没有说一条路径上只能删一条边的限制就可以直接最小流了,而有这个限制的话就给反向边建inf,然后给能dfs到的点跑个最小割就可以了(其实是没懂的)

    Code

    Show Code
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    typedef long long ll;
    const int N = 105;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar())
            if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar())
            x = x * 10 + c - '0';
        return x * f;
    }
    
    struct Edge {
        int n, t; ll d;
    }e[N*N>>1];
    int h[N], edc = 1;
    
    void Add(int x, int y, ll z) {
        e[++edc] = (Edge) {h[x], y, z}; h[x] = edc;
    }
    
    ll ans;
    bool v[N];
    int n, dep[N], q[N], l, r, tmp[N];
    
    void Dfs(int x) {
        v[x] = 1;
        for (int i = h[x], y; i; i = e[i].n)
            if (!v[y=e[i].t] && e[i].d != 1e12) Dfs(y);
    }
    
    bool Bfs() {
        memset(dep + 1, 0, n * 4);
        memcpy(h + 1, tmp + 1, n * 4);
        dep[1] = 1; q[l=r=1] = 1;
        while (l <= r) {
            int x = q[l++];
            for (int i = h[x], y; i; i = e[i].n) {
                if (!v[y=e[i].t] || !e[i].d || dep[y]) continue;
                dep[y] = dep[x] + 1; q[++r] = y;
                if (y == n) return 1;
            }
        }
        return 0;
    }
    
    ll Dinic(int x, ll lim) {
        if (x == n) return lim;
        ll sum = 0;
        for (int i = h[x]; i && lim; i = e[i].n) {
            int y = e[i].t; h[x] = i;
            if (!e[i].d || dep[y] != dep[x] + 1) continue;
            ll f = Dinic(y, min(lim, e[i].d));
            sum += f; lim -= f;
            e[i].d -= f; e[i^1].d += f;
        }
        if (!sum) dep[x] = 0;
        return sum;
    }
    
    int main() {
        n = read();
        for (int m = read(); m; --m) {
            int x = read() + 1, y = read() + 1, z = read();
            Add(x, y, z); Add(y, x, 1e12);
        }
        Dfs(1);
        if (!v[n]) return puts("-1"), 0;
        memcpy(tmp + 1, h + 1, n * 4);
        while (Bfs()) ans += Dinic(1, 1e12);
        printf("%lld
    ", ans >= 1e12 ? -1ll : ans);
        return 0;
    }
    
  • 相关阅读:
    Codeforces Round #609 (Div. 2)
    Educational Codeforces Round 78 (Rated for Div. 2)
    Codeforces
    crontab
    C6 C7的开机启动流程
    平均负载压力测试
    ps 和 top
    if判断
    使用3种协议搭建本地yum仓库
    linux rpm包
  • 原文地址:https://www.cnblogs.com/shawk/p/14369926.html
Copyright © 2020-2023  润新知