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();
    }
}
posted @ 2025-10-11 14:27  arin876  阅读(5)  评论(0)    收藏  举报