其他分享
首页 > 其他分享> > 伪模板————主席树

伪模板————主席树

作者:互联网

P3701: https://www.luogu.com.cn/problem/P3701

这道题是网络流一道经典的题目

不过有两个不科学的坑点

既然是网络流,那么关键点自然是在建图上

我们把我们的点叫a,对方的点叫b,源点是s,汇点是t


 

我们思考,由于life的限制,所以我们体现在图上就是:

对每一个a从s连一条长life的边

对每一个b连一条长life的边到t

这样我们就能保证life的限制


 

接下来,考虑,由于我们要求的是赢的最多的

所以我们只要考虑我们能赢的关系就可以了

如果a能赢b那么从a连一条长为1的边,保证两两只会打一场比赛


接下来就要考虑续命的问题了

本来根据蛤一定律,即时间守恒定律:时间不会凭空产生或消失,只会从一个人转移到另一个人。

所以我们可以考虑,我们让膜法师续给主席1s,即把膜法师的1*life续给主席,表现在图上就是把膜法师的一个流量分给主席

即对于每个膜法师,向每一个主席连一条长为1的边,表示每个膜法师能分给每个主席1流量

然而,这道题不遵循时间守恒定律,即膜法师可以不用减少自己的时间给主席续命,这是第一个坑点

就要思考,如何在不消耗自己时间的情况下续命:当然是让别人给主席续命了

所以我们可以建立一些虚点,数量与己方膜法师数量相等,从s连一条inf的边(反正续不死,爱续多少续多少),然后向己方每一位主席建一条长度为1的边(每位膜法师只能给每位主席续1s)


至于对方,

考虑到我们只考虑了我们能赢的关系,在对方那么,对我们来说我们不会和它能赢的打,所以对对手来说,其实他们死的越快输的越少

所以,对于对手,给主席续命一定是非最优决策,所以可以不考虑

这样建完后,dinic,交一发——>90

嗯?嗯??嗯???

没错啊,为什么只有90,难道对手也会续命,一改,果然

所以我们也要类似自己的方法一样建虚点,连边,这是第二个坑点

然后跑dinic就可以了

 


#include<bits/stdc++.h>
#define il inline
using namespace std;
const int N = 2e3+4;
int n,m,s,t;
struct edge
{
    int next,to,w;
}p[200*N];
int head[N],num;
il void ad(int x,int y,int z){p[++num]=edge{head[x],y,z};head[x]=num;}
il void add(int x,int y,int z)
{
    ad(x,y,z);
    ad(y,x,0);
//    printf("%d %d %d\n",x,y,z);
}
il int qfj(int x){return ((x-1)^1)+1;}
int dep[N],cur[N];
bool bfs(int s,int t)
{
    for(int i=s;i<=t;i++) cur[i]=head[i];
    queue<int> q;
    q.push(s);
    memset(dep,0,sizeof(dep));
    dep[s]=1;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=head[u];i;i=p[i].next)
        {
            int v=p[i].to;
            if(!dep[v]&&p[i].w)
            {
                dep[v]=dep[u]+1;
                q.push(v);
            }
        }
    }
    //printf("%d\n",dep[t]);
    return dep[t];
}
int dfs(int u,int t,int limit)
{
    if(u==t||!limit) return limit;
    int flow=0,w;
    for(int i=head[u];i;i=p[i].next)
    {
        int v=p[i].to;
        if(dep[v]==dep[u]+1&&(w=dfs(v,t,min(limit,p[i].w))))
        {
    //        printf("%d %d %d\n",u,v,w);
            p[i].w-=w;
            flow+=w;
            p[qfj(i)].w+=w;
            limit-=w;
            if(!limit) break;
        }
    }
    return flow;
}
int dinic(int s,int t)
{
    int mxfl=0;
    while(bfs(s,t)) mxfl+=dfs(s,t,1e9);
    return mxfl;
}
int ans;
int a[N],lf[N],w1[9],w2[9];
int main()
{
//    freopen("3376.out","w",stdout);
    cin>>n>>m;
    int x=0,y=0;
    for(int i=1;i<=n;i++)
    {
        string s;
        cin>>s;
    //    cout<<s<<endl;
        if(s[0]=='Y') 
        {
            a[i]=1;
            x++;
        }
        if(s[0]=='H') a[i]=2;
        if(s[0]=='W') a[i]=3;
        if(s[0]=='J') a[i]=4;
        if(s[0]=='E') a[i]=5;
    }
    for(int i=n+1;i<=n+n;i++)
    {
        string s;
        cin>>s;
        if(s[0]=='Y') 
        {
            a[i]=1;
            y++;
        }
        if(s[0]=='H') a[i]=2;
        if(s[0]=='W') a[i]=3;
        if(s[0]=='J') a[i]=4;
        if(s[0]=='E') a[i]=5;
    }
    for(int i=1;i<=n+n;i++) scanf("%d",lf+i);
    s=0;t=n+n+1+x+y;
    w1[1]=2;w2[1]=4;
    w1[2]=3;w2[2]=5;
    w1[3]=1;w2[3]=5;
    w1[4]=2;w2[4]=3;
    w1[5]=1;w2[5]=4;
    for(int i=1;i<=n;i++) add(s,i,lf[i]);
    for(int i=n+1;i<=n+n;i++) add(i,t,lf[i]);
    for(int i=1;i<=n;i++)
        for(int j=n+1;j<=n+n;j++)
            if(a[j]==w1[a[i]]||a[j]==w2[a[i]])
            {
                add(i,j,1);
//                printf("#%d %d %d %d %d\n",i,j,a[j],w1[i],w2[i]);
            }
//    printf("%d %d\n",s,t);
    for(int i=n+n+1;i<=n+n+x;i++)
    {
        add(s,i,1e9);
        for(int j=1;j<=n;j++) if(a[j]==4) add(i,j,1);
    }
    for(int i=n+n+1+x;i<t;i++)
    {
        add(i,t,1e9);
        for(int j=n+1;j<=n+n;j++) if(a[j]==4) add(j,i,1e9);
    }
    ans=dinic(s,t);
    cout<<min(ans,m);
    return 0;
}

这个故事告诉我们:

给主席续命是绝对的!无论何时,无论何地,无论何种情况,无论对我们是否有利,我们都要续,要加大力度地续

 

标签:int,dep,limit,模板,续命,主席,法师
来源: https://www.cnblogs.com/shenbear/p/12269548.html