P3701 「伪模板」主席树
Posted five20
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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能赢的场次
输入输出样例
3 3
J W YYY
J HK E
2 2 2
2 2 2
3
说明
第一场主席赢记者,第二场高人赢女王,第三场膜法师赢记者。
Solution:
本题最大流。
读完题后,不难发现是一张二分图的模型,而且角色克制关系也给定了,那么就是个傻逼建图了。
我们由源点向byx的每个人连边流量为生命值,由手气君的每个人向汇点连边流量为生命值,对于byx的每个节点按照击败关系向手气君的节点连边流量为$1$,由于$YYY$可以为每个$J$加血,所以统计下byx和手气君各自的$YYY$个数,再对于各自的$J$都补建$YYY$个数为流量的边就好了。(开始WA的原因:注意不能直接统计角色总血量然后对每种角色建图,因为两个角色之间只能比一次,而且每个$YYY$可以为每个$J$加一次血,都有流量限制,所以只能$n^2$建图)
代码:
/*Code by 520 -- 9.25*/ #include<bits/stdc++.h> #define il inline #define ll long long #define RE register #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++) #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--) using namespace std; const int N=100005,inf=233333333; int n,m,s,t,dis[520],a[6],b[6]; int to[N],net[N],w[N],cnt=1,h[N]; map<string,int>mp; il void add(int u,int v,int c){ to[++cnt]=v,net[cnt]=h[u],h[u]=cnt,w[cnt]=c; to[++cnt]=u,net[cnt]=h[v],h[v]=cnt,w[cnt]=0; } queue<int>q; bool bfs(){ memset(dis,-1,sizeof(dis)); dis[s]=0,q.push(s); while(!q.empty()){ RE int u=q.front();q.pop(); for(RE int i=h[u];i;i=net[i]) if(w[i]&&dis[to[i]]==-1) dis[to[i]]=dis[u]+1,q.push(to[i]); } return dis[t]!=-1; } int dfs(int u,int op){ if(u==t) return op; int flow=0,used=0; for(RE int i=h[u];i;i=net[i]){ int v=to[i]; if(w[i]&&dis[to[i]]==dis[u]+1){ used=dfs(to[i],min(w[i],op)); if(!used) continue; flow+=used,op-=used; w[i]-=used,w[i^1]+=used; if(!op) break; } } if(!flow) dis[u]=-1; return flow; } int main(){ scanf("%d%d",&n,&m),t=250; mp["J"]=1,mp["HK"]=2,mp["W"]=3,mp["YYY"]=4,mp["E"]=5; string ca[105],cb[105];int na[105],nb[105]; int ta=0,tb=0; For(i,1,n) cin>>ca[i]; For(i,1,n) cin>>cb[i]; For(i,1,n) { cin>>na[i],add(s,i,na[i]); if(mp[ca[i]]==4) ta++; } For(i,1,n) { cin>>nb[i],add(i+100,t,nb[i]); if(mp[cb[i]]==4) tb++; } For(i,1,n) { if(mp[ca[i]]==1) add(s,i,ta); if(mp[cb[i]]==1) add(i+100,t,tb); } For(i,1,n) For(j,1,n){ int p=mp[ca[i]],q=mp[cb[j]]; if(p==1&&(q==3||q==2)) add(i,j+100,1); if(p==2&&(q==3||q==5)) add(i,j+100,1); if(p==3&&(q==4||q==5)) add(i,j+100,1); if(p==4&&(q==2||q==1)) add(i,j+100,1); if(p==5&&(q==1||q==4)) add(i,j+100,1); } int ans=0; while(bfs()) ans+=dfs(s,inf); cout<<min(ans,m); return 0; }
以上是关于P3701 「伪模板」主席树的主要内容,如果未能解决你的问题,请参考以下文章