省选测试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\n", 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\n", pow(2, ans));
    return 0;
}
posted @ 2021-03-25 14:09  Shawk  阅读(31)  评论(0编辑  收藏  举报