AtCoder Beginner Contest 395
D - Pigeon Swap
想到并查集,挂在哪个点上
其实也用不上并查集
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define yes cout << "Yes" << endl
#define no cout << "No" << endl
#define pii pair<int,int>
#define ll long long
#define pb push_back
#define ft first
#define se second
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define int long long
const int N=1000010;
/*
5
3
1 1 2
1 1 4
3 2
*/
/*
5
4
1 1 2
2 2 4
3 1
3 2
*/
int n,q;
int mp[2*N];int nmp[N];int fa[2*N];
int findd(int x){
while(x!=fa[x])x=fa[x]=fa[fa[x]];return x;
}
void solve(){
cin>>n>>q;
for(int i=1;i<=n;i++)mp[i+n]=i;
for(int i=1;i<=n;i++){
fa[i]=i+n;//挂载i节点,i节点编号为mp[i]
fa[i+n]=i+n;
nmp[i]=i+n;
}
while(q--){
int op;cin>>op;
if(op==1){
int a,b;cin>>a>>b;
fa[a]=nmp[b];
}else if(op==2){
int a,b;cin>>a>>b;
a=nmp[a];b=nmp[b];
swap(nmp[mp[a]],nmp[mp[b]]);
swap(mp[a],mp[b]);
}else {
int a;cin>>a;
cout<<mp[findd(a)]<<'\n';
}
}
}
signed main(){
std::ios::sync_with_stdio(false);
int T;T=1;
while(T--){
solve();
}
}
E - Flip Edge
最短路,加入翻转操作
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define yes cout << "Yes" << endl
#define no cout << "No" << endl
#define pii pair<int,int>
#define ll long long
#define pb push_back
#define ft first
#define se second
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define int long long
#define piii pair<int,pair<int,int>>
const int N=200010;int n,m,X;
vector<int> G[2][N];
int d[N][2];bool st[N][2];
void dijk(){
priority_queue<piii,vector<piii>,greater<piii>> heap;
for(int i=1;i<=n;i++)d[i][0]=d[i][1]=INF;
heap.push({0,{1,0}});d[1][0]=0;heap.push({X,{1,1}});d[1][1]=X;
while(!heap.empty()){
auto tmp=heap.top();heap.pop();
int d1=tmp.ft;int u=tmp.se.ft;int sta=tmp.se.se;
if(st[u][sta])continue;st[u][sta]=1;
for(auto v:G[sta][u]){
if(d[v][sta]>d[u][sta]+1){
d[v][sta]=d[u][sta]+1;
heap.push({d[v][sta],{v,sta}});
}
}
for(auto v:G[sta^1][u]){
if(d[v][sta^1]>d[u][sta]+X+1){
d[v][sta^1]=d[u][sta]+X+1;
heap.push({d[v][sta^1],{v,sta^1}});
}
}
}
}
void solve(){
cin>>n>>m>>X;
while(m--){
int u,v;cin>>u>>v;G[0][u].pb(v);G[1][v].pb(u);
}
dijk();
cout<<min(d[n][0],d[n][1])<<'\n';
}
signed main(){
std::ios::sync_with_stdio(false);
int T;T=1;
while(T--){
solve();
}
}
F - Smooth Occlusion
常见的思路
磨掉的牙齿越少,留下的越多
二分h,就是移动区间check的经典方法
由于最后是正好上牙+下牙=h,而必然存在一个方案满足找出来的h,所以用上牙下牙的和-n*h
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define yes cout << "Yes" << endl
#define no cout << "No" << endl
#define pii pair<int,int>
#define ll long long
#define pb push_back
#define ft first
#define se second
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define int long long
const int N=200010;
int n,X;
int a[N],a1[N];
pair<int,int> intersect(pii p1,pii p2){
int l=max(p1.ft,p2.ft);int r=min(p1.se,p2.se);
if(l>r)return {-1,-1};
return {l,r};
}
bool ck(int mid){
pii lr={0,1e18};
for(int i=1;i<=n;i++){
lr.ft=max(0ll,lr.ft-X);lr.se+=X;
lr=intersect(lr,{max(0ll,mid-a1[i]),a[i]});
if(lr.ft==-1)return 0;
}
return 1;
}
int get(int mid){
int res=0;for(int i=1;i<=n;i++)res+=a[i]+a1[i];
return res-n*mid;
}
void solve(){
cin>>n>>X;
for(int i=1;i<=n;i++)cin>>a[i]>>a1[i];
int l=0;int r=2e9;
while(l<r){//二分h
int mid=(l+r+1)>>1;
if(ck(mid))l=mid;
else r=mid-1;
}
cout<<get(l)<<'\n';
}
signed main(){
std::ios::sync_with_stdio(false);
int T;T=1;
while(T--){
solve();
}
}

浙公网安备 33010602011771号