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

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

<题目链接>



这是一道网络流,不是主席树,不是什么数据结构,而是网络流。

题目背景及描述都非常的暴力,以至于 Capella 在做此题的过程中不禁感到生命流逝。

S 向 byx 的树中的每一个人连有向边,手气君的树中的每一个人向 T 连有向边,边权为这个人的寿命。统计同一棵树中的膜法师数量 x。如果一个人是主席,那么边权要加上 x。(续得好啊

然后,如果 byx 树中的一个点 i 能赢手气君树中的点 j,那么连 i->j,边权为 1。

跑最大流,最终答案为 min(m,ans)。

PS:指针邻接表写网络流真有意思,我再也不用写什么 ((i-1)^1)+1 蛇皮操作了!开心!

以及悄悄在代码里表白一下 Procyon。qwqqwqqwq

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
using std::min;
using std::queue;
const int MAXN=210,INF=0x3f3f3f3f;
int n,m,S,T,win[5][5]={ {0  ,1  ,1  ,-1 ,-1 },
                        {-1 ,0  ,1  ,1  ,-1 },
                        {-1 ,-1 ,0  ,1  ,1  },
                        {1  ,-1 ,-1 ,0  ,1  },
                        {1  ,1  ,-1 ,-1 ,0  }};
struct Edge
{
    int to,w;
    Edge *nxt,*back;
    Edge(int to=0,int w=0,Edge* nxt=nullptr):to(to),w(w),nxt(nxt),back(nullptr){}
    ~Edge(void)
    {
        if(nxt!=nullptr)
            delete nxt;
    }
}*head[MAXN];
void AddEdges(int u,int v,int w)
{
    head[u]=new Edge(v,w,head[u]);
    head[v]=new Edge(u,0,head[v]);
    head[u]->back=head[v];
    head[v]->back=head[u];
}
int Number(char *s)
{
    if(s[0]==‘J‘)
        return 0;
    else if(s[0]==‘H‘)
        return 1;
    else if(s[0]==‘W‘)
        return 2;
    else if(s[0]==‘E‘)
        return 3;
    else if(s[0]==‘Y‘)
        return 4;
}
void InitTree(int *a)
{
    char s[5];
    for(int i=1;i<=n;++i)
    {
        scanf(" %s",s);
        a[i]=Number(s);
        if(a[i]==4)
            ++a[0];
    }
}
void Init(void)
{
    static int a[MAXN],b[MAXN];
    T=(n<<1)+1;
    InitTree(a);
    InitTree(b);
    for(int i=1;i<=n;++i)
        head[i]=nullptr;
    for(int i=1,x;i<=n;++i)
    {
        scanf("%d",&x);
        AddEdges(S,i,!a[i] ? x+a[0] : x);
    }
    for(int i=1,x;i<=n;++i)
    {
        scanf("%d",&x);
        AddEdges(i+n,T,!b[i] ? x+b[0] : x);
    }
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
            if(win[a[i]][b[j]]==1)
                AddEdges(i,j+n,1);
}
void Destroy(void)
{
    for(int i=S;i^T;++i)
        delete head[i];
}
namespace Procyon
{
    int dis[MAXN];
    Edge *cur[MAXN];
    bool BFS(int S,int T)
    {
        queue<int> q;
        memset(dis,0,sizeof dis);
        q.push(S);
        dis[S]=1;
        while(!q.empty())
        {
            int u=q.front(),v;
            q.pop();
            for(Edge *i=head[u];i!=nullptr;i=i->nxt)
                if(i->w && !dis[v=i->to])
                {
                    q.push(v);
                    dis[v]=dis[u]+1;
                }
        }
        return dis[T];
    }
    int DFS(int u,int k)
    {
        if(u==T || !k)
            return k;
        int v,f,sum=0;
        for(Edge *&i=cur[u];i!=nullptr;i=i->nxt)
            if(i->w && dis[v=i->to]==dis[u]+1 && (f=DFS(v,min(k,i->w))))
            {
                k-=f;
                sum+=f;
                i->w-=f;
                i->back->w+=f;
            }
        if(!sum)
            dis[u]=1;
        return sum;
    }
    void Dinic(int S,int T)
    {
        int ans=0;
        while(BFS(S,T))
        {
            memcpy(cur,head,sizeof head);
            ans+=DFS(S,INF);
        }
        printf("%d\n",min(m,ans));
    }
}
int main(int argc,char** argv)
{
    scanf("%d %d",&n,&m);
    Init();
    Procyon::Dinic(S,T);
    Destroy();
    return 0;
}

谢谢阅读。

原文地址:https://www.cnblogs.com/Capella/p/9069178.html

时间: 2024-10-10 09:40:26

[Luogu 3701] 「伪模板」主席树的相关文章

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

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

P3701 「伪模板」主席树

P3701 「伪模板」主席树 题目背景 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

Luogu Dynamic Ranking (带修改的主席树)

带修改的主席树: 原本的主席树是维护了一个线段树前缀. 那么前缀有没有想到什么东西? 树状数组\(Bits\)是不是很 ...... ? 那么现在,我们用树状数组套主席树,不就可以实现带修改的可持久化了吗. 具体来说 \(T[1]维护rt[1]\) , \(T[2]维护rt[1].rt[2]\) , \(T[3]维护rt[3]\) ...... 就与树状数组是一样的. 那么现在,两个具体的操作: 修改: 修改需要修改\(logN\)棵主席树,将涉及修改节点的\(log\)个主席树先删后加点即可.

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

相关讲解资料: 树状数组: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> #

Luogu P2323「皇后游戏」

算是数论吧,证明出来一个公式之后就可以据此把所有大臣排序,然后求最后一位大臣的奖励即为答案. 证明: 考虑相邻的大臣是否交换.设某个编号为 $ i $ 的大臣,后面一位编号为 $ j $ .设i前面所有大臣的 $ a $ 值之和为 $ x $ ,设 $ c[i-1] $ 为 $ y $ .如果不交换 $ i $ 和 $ j $ ,则 $ c $ 值较大的大臣的 $ c $ 值为 $ max(max(x+a_i,y)+b_i,x+a_i+a_j)+b_j $ 化简: $ max(x+a_i+b_i