题意:x轴上有n个点,分别有三种颜色(BRP),两点之间连边的代价为其距离.
要求删除红色点R时,BP中的任意两点能联通.
要求删除蓝色点B时,RP中的任意两点能联通.
n<=2e5, -1e9<=x[i]<=1e9. 问满足以上条件的最小建边代价?
若没有P点 则连接相邻的B,和连接相邻的R即可.
例子:RPR 显然这连接R-P-R,比[R-R,R-P]来的优
先将在第一个P之前的相邻点依次连接,在最后一个P后面的相邻点依次连接.
然后相邻两个P之间的情况可以独立来考虑,P....P, 先考虑B,然后R也类似考虑.
情况1:相邻的P不连接,分别连接相邻的B,BP即可.
情况2: 连接相邻的P, P.b[1],b[2],...b[i]...b[k],P 总共k+2个点 边肯定都是相邻的.
要求删除红色点R时,BP中的任意两点能联通.
要求删除蓝色点B时,RP中的任意两点能联通.
n<=2e5, -1e9<=x[i]<=1e9. 问满足以上条件的最小建边代价?
若没有P点 则连接相邻的B,和连接相邻的R即可.
例子:RPR 显然这连接R-P-R,比[R-R,R-P]来的优
先将在第一个P之前的相邻点依次连接,在最后一个P后面的相邻点依次连接.
然后相邻两个P之间的情况可以独立来考虑,P....P, 先考虑B,然后R也类似考虑.
情况1:相邻的P不连接,分别连接相邻的B,BP即可.
情况2: 连接相邻的P, P.b[1],b[2],...b[i]...b[k],P 总共k+2个点 边肯定都是相邻的.
要联通只需要k+1条边.所以去掉相邻间距最大的一条边即可.
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=3e5+5; ll n,x; char op[2]; struct node{ ll x; char op; }a[N]; ll res=0; void calc() { ll mxR=-2e9,mxB=-2e9,mnR=2e9,mnB=2e9; for(int j=1;j<=n;j++) { if(a[j].op=='R') mxR=max(mxR,a[j].x),mnR=min(mnR,a[j].x); if(a[j].op=='B') mxB=max(mxB,a[j].x),mnB=min(mnB,a[j].x); } if(mxR!=-2e9) res+=mxR-mnR; if(mxB!=-2e9) res+=mxB-mnB; cout<<res<<'\n'; exit(0); } int main() { scanf("%I64d",&n); for(int i=1;i<=n;i++) { scanf("%I64d%s",&a[i].x,op); a[i].op=op[0]; } int st=-1,ed=-1; for(int i=1;i<=n;i++) if(a[i].op=='P') { ll mnR=2e9,mnB=2e9; for(int j=1;j<i;j++) { if(a[j].op=='R') mnR=min(mnR,a[j].x); if(a[j].op=='B') mnB=min(mnB,a[j].x); } if(mnR!=2e9) res+=a[i].x-mnR; if(mnB!=2e9) res+=a[i].x-mnB; st=i; break; } if(st==-1) calc(); for(int i=n;i>=1;i--) if(a[i].op=='P') { ll mxR=-2e9,mxB=-2e9; for(int j=i+1;j<=n;j++) { if(a[j].op=='R') mxR=max(mxR,a[j].x); if(a[j].op=='B') mxB=max(mxB,a[j].x); } if(mxR!=-2e9) res+=mxR-a[i].x; if(mxB!=-2e9) res+=mxB-a[i].x; ed=i; break; } for(int i=st,j=i;i!=ed;i=j) { j++; while(j<=n&&a[j].op!='P') j++; ll mn=1e18,sum=0; ll pr=a[i].x,pb=a[i].x,mr=0,mb=0; for(int k=i;k<j;k++) { if(a[k].op=='R') { mr=max(mr,a[k].x-pr); pr=a[k].x; } if(a[k].op=='B') { mb=max(mb,a[k].x-pb); pb=a[k].x; } } if(pb!=a[i].x) mb=max(mb,a[j].x-pb),sum+=a[j].x-a[i].x-mb; if(pr!=a[i].x) mr=max(mr,a[j].x-pr),sum+=a[j].x-a[i].x-mr; if(pb!=a[i].x&&pr!=a[i].x) mn=min(mn,2ll*(a[j].x-a[i].x)); sum+=a[j].x-a[i].x; mn=min(mn,sum); res+=mn; } cout<<res<<'\n'; return 0; }
每个B和R不会越过P连边 所以遇到p时可以把当前p位置当做最后一个B和R来看待,大大简化的代码量
#include<bits/stdc++.h> #define MAXN 300005 #define INF 1000000000 #define MOD 1000000007 #define F first #define S second using namespace std; typedef long long ll; typedef pair<ll,ll> P; ll n,x,lastr,lastb,lastp,mr,mb,ans=0; char ch; int main() { scanf("%I64d",&n); bool pp=false,bb=false,rr=false; for(ll i=1;i<=n;i++) { scanf("%I64d %c",&x,&ch); if(ch=='R'||ch=='P') { if(rr) { ans+=x-lastr; mr=max(mr,x-lastr); } rr=true; lastr=x; } if(ch=='B'||ch=='P') { if(bb) { ans+=x-lastb; mb=max(mb,x-lastb); } bb=true; lastb=x; } if(ch=='P') { if(pp)ans+=min(0LL,x-lastp-mr-mb); lastp=x;mr=0;mb=0;pp=true; } } printf("%I64d\n",ans); return 0; }