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无力吐槽

原文地址:https://www.cnblogs.com/hkttg/p/9426886.html

时间: 2024-08-30 03:35:25

P3701 「伪模板」主席树的相关文章

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

[Luogu 3701] 「伪模板」主席树 <题目链接> 这是一道网络流,不是主席树,不是什么数据结构,而是网络流. 题目背景及描述都非常的暴力,以至于 Capella 在做此题的过程中不禁感到生命流逝. S 向 byx 的树中的每一个人连有向边,手气君的树中的每一个人向 T 连有向边,边权为这个人的寿命.统计同一棵树中的膜法师数量 x.如果一个人是主席,那么边权要加上 x.(续得好啊) 然后,如果 byx 树中的一个点 i 能赢手气君树中的点 j,那么连 i->j,边权为 1. 跑最大

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

题目背景 byx和手气君都非常都非常喜欢种树.有一天,他们得到了两颗奇怪的树种,于是各自取了一颗回家种树,并约定几年后比一比谁种出来的树更加牛x. 题目描述 很快,这棵树就开花结果了.byx和手气君惊讶的发现,这是一棵主席树,树上长满了主席和主席的朋友们.这棵树上一共有五种人,主席(J),记者(HK),高人(W),女王(E)和膜法师(YYY).他们发现,他们的主席树上的人数相同,都为N.   研究发现,这五种人的输赢如上图所示(一样的人不能PK),箭头指向输的人.至于为什么,留给同学们自己思考.

「模板」 线段树——区间乘 &amp;&amp; 区间加 &amp;&amp; 区间求和

「模板」 线段树--区间乘 && 区间加 && 区间求和 <题目链接> 原来的代码太恶心了,重贴一遍. #include <cstdio> int n,m; long long p; class SegmentTree { private: struct Node { int l,r; long long v,mul,add; Node *c[2]; Node(int l,int r):l(l),r(r),mul(1LL),add(0LL) { c[

【Luogu】P3384主席树模板(主席树查询K小数)

YEAH!我也是一个AC主席树模板的人了! 其实是个半吊子 我将尽量详细的讲出我的想法. 主席树太难,我们先搞普通线段树好了 普通线段树怎么做?我的想法是查询K次最小值,每次查完把查的数改成INF,查完再改回来... MDZZ 于是就有了主席树. 先不考虑主席树,我们来考虑一个奇特的线段树. 一般的线段树,数列位置是下标,而把数列维护值作为线段树中存的元素. 那我们如果反过来,把数列元素当做线段树的下标...??? 比如说数列[4 2 3 1] 如果线段树的下标是1.2.3.4......? 那

「不会」矩阵树定理

定理不会证,也不会用 「小z的房间」 暴力建图 「重建」 矩阵树求的是$\sum\limits_{T} \prod\limits_{e\in T} w(e)$ 而要求的是$\sum\limits_{T} \prod\limits_{e\in T}p(e)*\prod\limits_{e isnot\in T} 1-p(e)$ 即$\prod\limits_e 1-p(e) \sum\limits_{T} \prod\limits_{e\in T}p(e)/(1-p(e))$ 设$w(e)=p(e

【模板】主席树

主席树..高大上的名字..原名叫可持久化线段树..也有人叫函数式线段树(其实叫什么都不重要). 本来的作用就是字面意思..持久化的线段树,支持修改之后查找某次修改之前的版本.(在NOIP之前在算法导论上看到过,当时觉得没什么,现在才知道好厉害的数据结构) 具体来怎么实现呢..其实就是每次修改的时候都新开一个根节点然后把和修改有关的区间一路新建下去,与修改无关的区间就继承上次修改版本的节点,这样会节省空间. 来应用一下,一个基础的应用就是区间K小值查询(poj2104).即给定一个序列,给出L,R

「模板」线段树静态开点(单点+区间修改)、动态开点

相关讲解资料: 树状数组:https://blog.csdn.net/qq_34374664/article/details/52787481 (线段树预备) 线段树讲解: 初学版:https://blog.csdn.net/zearot/article/details/52280189 进阶完整版:https://www.cnblogs.com/AC-King/p/7789013.html 代码: 完整注释模板一张,参(chao)考(xi)楼上的博客 #include<iostream> #

【模板】 主席树

1 // poj2104 2 // p3834 3 #include<iostream> 4 #include<cstdio> 5 #include<algorithm> 6 using namespace std; 7 const int N=1e5+7; 8 int a[N],b[N],rt[N]; 9 int cnt=0; 10 struct node{ 11 int l,r,sum; 12 }tr[N*20]; 13 void build(int& o,

P3834 【模板】主席树

题目地址 注意点: MAXN可开到1e7. #include<cstdio> #include<iostream> using namespace std; const int MAXN=1e7,INF=2e9; struct Node{ int ls,rs; int cnt; }tr[MAXN]; int nodeCnt=0; void insert(int p,int &q,int l,int r,int val){ if(!q)q=++nodeCnt; if(l==r