• 省选测试46



    又倒第一了,流汗黄豆稳了

    A 签到题

    题目大意 : 每个点有个到最后的单调栈,会有修改和询问

    • 转换一下题意,找到后面第一个比自己大的点向自己连边,就形成了个森林,建个超级源点,就成了颗树

    • 修改操作就变成了把x和x的一级儿子都加上v,询问操作变成了查找x,y路径上的和,如果x,y的lca是x或y,那么还要再加上fa[lca]的值

    • 询问好搞,树剖就行,问题是如何修改x和x的所有儿子。由于有树剖,可以考虑只修改x和x的重儿子,给x记一个标记,然后跳轻边的时候加上fa[tp]的标记

    • 最后一条链如果链顶是tp的话,还得加上fa[tp]的标记,lca是xy的要特殊处理一下

    Code

    Show Code
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    typedef long long ll;
    const int N = 2e5 + 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;
    }e[N];
    int h[N], edc;
    
    void Add(int x, int y) {
        e[++edc] = (Edge) {h[x], y}; h[x] = edc;
    }
    
    ll t[N], s[N], ans;
    int n, m, a[N], stk[N], top, dep[N], sz[N], son[N], fa[N], tp[N], dfn[N], dfc;
    
    void Dfs(int x) {
        dep[x] = dep[fa[x]] + 1; sz[x] = 1;
        for (int i = h[x], y; i; i = e[i].n) {
            if ((y = e[i].t) == fa[x]) continue;
            fa[y] = x; Dfs(y); sz[x] += sz[y];
            if (sz[son[x]] < sz[y]) son[x] = y;
        }
    }
    
    void Dfs(int x, int top) {
        tp[x] = top; dfn[x] = ++dfc;
        if (son[x]) Dfs(son[x], top);
        for (int i = h[x], y; i; i = e[i].n)
            if ((y = e[i].t) != fa[x] && y != son[x]) Dfs(y, y);
    }
    
    void Modify(int x, int w) {
        for (; x <= dfc; x += x & -x) t[x] += w;
    }
    
    ll Ask(int l, int r, ll ans = 0) {
        for (; r; r -= r & -r) ans += t[r];
        for (l--; l; l -= l & -l) ans -= t[l];
        return ans;
    }
    
    int main() {
        freopen("set.in", "r", stdin);
        freopen("set.out", "w", stdout);
        n = read(); m = read();
        for (int i = 1; i <= n; ++i)
            a[i] = read();
        stk[++top] = n + 1; a[n+1] = 1e9;
        for (int i = n; i >= 1; --i) {
            while (top && a[i] >= a[stk[top]]) top--;
            Add(stk[top], i); stk[++top] = i;
        }
        Dfs(n + 1); Dfs(n + 1, n + 1);
        for (int i = 1; i <= n; ++i)
            Modify(dfn[i], read());
        while (m--) {
            int od = read(), x = read(), y = read(); ans = 0;
            if (od == 1) {
                Modify(dfn[x], y); s[x] += y; 
                if (son[x]) Modify(dfn[son[x]], y);
            }
            else {
                int tmp = dep[x] < dep[y] ? x : y;
                while (tp[x] != tp[y]) {
                    if (dep[tp[x]] < dep[tp[y]]) swap(x, y);
                    ans += Ask(dfn[tp[x]], dfn[x]); 
                    x = fa[tp[x]]; ans += s[x];
                }
                if (dfn[x] > dfn[y]) swap(x, y);
                if (x == n + 1 || (x == tmp && fa[x] == n + 1)) { puts("?"); continue; }
                ans += Ask(dfn[x], dfn[y]);
                if (x == tp[x]) ans += s[fa[x]];
                if (x == tmp) {
                    x = fa[tmp];
                    ans += Ask(dfn[x], dfn[x]);
                    if (x == tp[x]) ans += s[fa[x]];
                }
                printf("%lld
    ", ans);
            }
        }
        return 0;
    }
    

    B 蓝超巨星 (Unaccepted)

    题目大意 :

    Code

    Show Code

    C 秘密行动

    题目大意 : 每个位置的每个可选的质数有选和不算的代价,还有一些限制,两个位置选择某个质数的状态不同则还有个代价,问最小代价积

    • 除了我大概都能看出来是网络流吧。

    • 取对数可以做到把乘转换成加,就成了求最小代价和

    • s向每个位置的每个质数连选的代价,质数向t连不选的代价,限制的话就两个质数连双向边,流量为差异代价,然后跑最小割就行

    • 如果写Dinic是return的是lim-sum,那开始传进去的lim不能太大

    Code

    Show Code
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define double long double
    
    using namespace std;
    const int N = 505;
    
    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; double f;
    }e[N*2];
    int h[N], edc = 1, tmp[N];
    
    void Add(int x, int y, double d) {
        e[++edc] = (Edge) {h[x], y, d}; h[x] = edc;
        e[++edc] = (Edge) {h[y], x, 0}; h[y] = edc;
    }
    
    double f[N], ans;
    int n, m, id[N][N], s, t, idc, dep[N], q[N];
    
    bool Bfs() {
        memset(dep + 1, 0, t * 4);
        memcpy(h + 1, tmp + 1, t * 4);
        int l = 1, r = 1; q[1] = s; dep[s] = 1;
        while (l <= r) {
            int x = q[l++];
            for (int i = h[x], y; i; i = e[i].n) {
                if (!e[i].f || dep[y=e[i].t]) continue;
                dep[y] = dep[x] + 1; q[++r] = y;
                if (y == t) return 1;
            }
        }
        return 0;
    }
    
    double Dinic(int x, double lim) {
        if (x == t) return lim;
        double sum = 0;
        for (int i = h[x]; i && lim; i = e[i].n) {
            int y = e[i].t; h[x] = i;
            if (!e[i].f || dep[y] != dep[x] + 1) continue;
            double f = Dinic(y, min(lim, e[i].f));
            lim -= f; sum += f;
            e[i].f -= f; e[i^1].f += f;
        }
        if (!sum) dep[x] = 0;
        return sum;
    }
    
    int main() {
        freopen("secret.in", "r", stdin);
        freopen("secret.out", "w", stdout);
        n = read(); m = read();
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= 10; ++j)
                id[i][j] = ++idc;
        s = ++idc, t = s + 1;
        for (int i = 1, x; i <= 10; ++i)
            read(), scanf("%Lf", &f[i]);
        for (int i = 1; i <= n; ++i) {
            double x;
            for (int j = 1; j <= 10; ++j)
                scanf("%Lf", &x), Add(s, id[i][j], log2(x));
            for (int j = 1; j <= 10; ++j)
                scanf("%Lf", &x), Add(id[i][j], t, log2(x));
        }
        while (m--) {
            int x = read(), y = read(), z = read();
            Add(id[x][z], id[y][z], log2(f[z]));
            Add(id[y][z], id[x][z], log2(f[z]));
        }
        memcpy(tmp + 1, h + 1, t * 4);
        while (Bfs()) ans += Dinic(s, 1e18);
        printf("%.10Lf
    ", pow(2, ans));
        return 0;
    }
    
  • 相关阅读:
    XPah学习
    .NET在后置代码中输入JS提示语句(背景不会变白)
    .Net 使用文件上传控件FileUpload上传图片
    OnClientClick和OnClick同时使用!
    OnClientClick的用法
    mysql获得自增字段下一个值
    jQuery插件之ajaxFileUpload
    委托、匿名方法、Lambda表达式的演进
    js实现页面传值
    Entity Framework 学习初级篇--基本操作:增加、更新、删除、事务(转)
  • 原文地址:https://www.cnblogs.com/shawk/p/14565501.html
Copyright © 2020-2023  润新知