P3701 「伪模板」主席树

Posted hkttg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3701 「伪模板」主席树相关的知识,希望对你有一定的参考价值。

P3701 「伪模板」主席树

题目背景

byx和手气君都非常都非常喜欢种树。有一天,他们得到了两颗奇怪的树种,于是各自取了一颗回家种树,并约定几年后比一比谁种出来的树更加牛x。

题目描述

很快,这棵树就开花结果了。byx和手气君惊讶的发现,这是一棵主席树,树上长满了主席和主席的朋友们。这棵树上一共有五种人,主席(J),记者(HK),高人(W),女王(E)和膜法师(YYY)。他们发现,他们的主席树上的人数相同,都为N。

技术分享图片

研究发现,这五种人的输赢如上图所示(一样的人不能PK),箭头指向输的人。至于为什么,留给同学们自己思考。

比赛如期进行。

byx和手气君要进行M场比赛,每一场比赛他们会选出树上的两个人来比较看谁更牛x。

第i个人寿命为Lifei秒,每次比完赛他们就会-1s。当他们生命为0s时他们就不能再比赛了。

同时,当J的寿命为0时,同一棵树上的YYY可以为他+1s。每个YYY只能给.每个J续一次。

那么问题来了

现在给定N,M(1≤N≤100,1≤M≤1000),A和B每一个人所属种类(J,HK,W,YYY或E)以及每一个人的生命,生命不超过50.请你算算A最多能够赢得多少场比赛呢。

数据保证每一场一定都有人用。两个人之间只能比一场。

输入输出格式

输入格式:

第一行包含两个数N,M,含义看上面。

第二行N个字串(J,HK,W,YYY或E),表示byx的人所属种类,用空格隔开。

第三行N个字串(J,HK,W,YYY或E),表示手气君的人所属种类,用空格隔开。

第四行N个数,表示byx的人的生命。

第五行N个数,表示手气君的人的生命。

输出格式:

一个数,byx能赢的场次

输入输出样例

输入样例#1: 
3 3
J W YYY
J HK E
2 2 2
2 2 2
输出样例#1: 
3

说明

第一场主席赢记者,第二场高人赢女王,第三场膜法师赢记者。

——————————————————————————————————————————————————————————————————
标题都是骗人的

本来还以为是主席树……看了题面发现是网络流……

觉得发现了一道极水的黑题

但是调了2个多小时……

为什么呢?

    for (R int i = 1 + n; i <= 2 * n; ++ i) 
        AddEdge(i, T, hp2[i]), AddEdge(T, i, 0);
    for (R int i = 1; i <= n; ++ i) 
        AddEdge(i + n, T, hp2[i]), AddEdge(T, i + n, 0);

这两句……有区别吗?

但是第一个就是输出0啊

R是register……去掉也不管用……

为啥?为啥?为啥?

这种玄学错误我还能调出来真的是谢天谢地了

求大佬解惑

ACcode

#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <map>
#include <queue>
#define R register

typedef long long ll;
typedef double db;
const int INF = 1e9;
const int MAXM = 10010;
int n, m, hp1[110], hp2[110];
char name1[110][3], name2[110][3];
int ecnt = 1, head[MAXM], dep[MAXM];

struct Edge {
    int to, nxt, ret;
}e[MAXM];

inline int read() {
    int num = 0, f = 1; char ch = getchar();
    while (!isdigit(ch)) {if (ch == -) f = -1; ch = getchar();}
    while (isdigit(ch)) {num = num * 10 + ch - 0; ch = getchar();}
    return num * f;
}

void AddEdge(int x, int y, int c) {
    e[++ ecnt].to = y; e[ecnt].ret = c; 
    e[ecnt].nxt = head[x]; head[x] = ecnt;
}

int dfs(int x, int t, int maxFlow) {
    if (!maxFlow || x == t) return maxFlow;
    int ans = 0, v, f;
    for (int i = head[x]; i; i = e[i].nxt) {
        v = e[i].to;
        if (dep[v] == dep[x] + 1 && e[i].ret > 0) {
            f = dfs(v, t, std::min(maxFlow - ans, e[i].ret));
            e[i].ret -= f;
            e[i ^ 1].ret += f;
            ans += f;
        }
    }
    if (ans < maxFlow) dep[x] = n + 1;
    return ans;
}

bool bfs(int s, int t) {
    std::queue<int> q;
    memset(dep, -1, sizeof(dep));
    q.push(s);
    dep[s] = 0;
    int h, v;
    while (!q.empty()) {
        h = q.front(); q.pop();
        for (int i = head[h]; i; i = e[i].nxt) {
            v = e[i].to;
            if (e[i].ret > 0 && dep[v] == -1) {
                q.push(v);
                dep[v] = dep[h] + 1;
            }
        }
    } return dep[t] != -1;
}

int Dinic(int s, int t) {
    int ans = 0;
    while (bfs(s, t)) ans += dfs(s, t, INF);
    return ans;
}

int main() {
    n = read(), m = read();
    //std::cin >> n >> m;
    int add1 = 0, add2 = 0;
    for (R int i = 1; i <= n; ++ i) {
        scanf("%s", name1[i]);
        if (name1[i][0] == Y) ++ add1;
    }
    for (R int i = 1; i <= n; ++ i) {
        scanf("%s", name2[i]);
        if (name2[i][0] == Y) ++ add2;
    }
    for (R int i = 1; i <= n; ++ i) {
        hp1[i] = read();
        //std::cin >> hp1[i];
        if (name1[i][0] == J) hp1[i] += add1;
    }
    for (R int i = 1; i <= n; ++ i) {
        hp2[i] = read();
        //std::cin >> hp2[i];
        if (name2[i][0] == J) hp2[i] += add2;
    }
    int S = 0, T = 2 * n + 1;
    for (R int i = 1; i <= n; ++ i) 
        AddEdge(S, i, hp1[i]), AddEdge(i, S, 0);
    /*for (R int i = 1 + n; i <= 2 * n; ++ i) 
        AddEdge(i, T, hp2[i]), AddEdge(T, i, 0);*/
    for (R int i = 1; i <= n; ++ i) 
        AddEdge(i + n, T, hp2[i]), AddEdge(T, i + n, 0);
    for (R int i = 1; i <= n; ++ i) for (R int j = 1; j <= n; ++ j) {
        if (name1[i][0] == J && (name2[j][0] == W || name2[j][0] == H))
            AddEdge(i, j + n, 1), AddEdge(j + n, i, 0);
        if (name1[i][0] == W && (name2[j][0] == Y || name2[j][0] == E))
            AddEdge(i, j + n, 1), AddEdge(j + n, i, 0);
        if (name1[i][0] == H && (name2[j][0] == W || name2[j][0] == E))
            AddEdge(i, j + n, 1), AddEdge(j + n, i, 0);
        if (name1[i][0] == E && (name2[j][0] == Y || name2[j][0] == J))
            AddEdge(i, j + n, 1), AddEdge(j + n, i, 0);
        if (name1[i][0] == Y && (name2[j][0] == H || name2[j][0] == J))
            AddEdge(i, j + n, 1), AddEdge(j + n, i, 0);
    }    
    std::cout << std::min(Dinic(S, T), m) << std::endl;
    return 0;
}

QwQ无力吐槽

以上是关于P3701 「伪模板」主席树的主要内容,如果未能解决你的问题,请参考以下文章

[Luogu 3701] 「伪模板」主席树

洛谷 3701「伪模板」主席树(最大流)

主席树模板

主席树 模板

Yangk's 静态主席树-模板

主席树模板