ABC395

赛时通过:ABC

赛后通过:DEF

D

赛时写了个平衡树,T 飞了。

其实根本没有那么复杂。考虑设一个「位置」的概念,并维护 \(id_i\) 表示鸟 \(i\) 所在的鸟巢的「位置」,\(pos_i\) 表示鸟巢 \(i\) 所在的位置,\(nest_i\) 表示 「位置」\(i\) 的鸟巢。

对于移动操作,令 \(pos_b \to id_a\)

对于交换操作,交换 \(nest_{pos_a},nest_{pos_b}\)\(pos_a,pos_b\)

对于查询操作,输出 \(nest_{id_a}\)

实现
// LUOGU_RID: 208038555
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
using namespace std;

const int N=1e6+5;
int n,q;
int pigeon_pos[N],nest_pos[N],pos_nest[N];

int main(){
	ios::sync_with_stdio(0);
	cin>>n>>q;
	for(int i=1;i<=n;i++)
		pigeon_pos[i]=i,nest_pos[i]=i,pos_nest[i]=i;
	while(q--){
		int op,a,b;
		cin>>op>>a;
		if(op==1){
			cin>>b;
			pigeon_pos[a]=nest_pos[b];
		}
		else if(op==2){
			cin>>b;
			swap(pos_nest[nest_pos[a]],pos_nest[nest_pos[b]]);
			swap(nest_pos[a],nest_pos[b]);
		}
		else
			cout<<pos_nest[pigeon_pos[a]]<<'\n';
	}
	return 0;
}

反观这个题目,实际上我们暴力的瓶颈就在于交换操作,而此种解法则使用设置中间量的方法,建立鸟与鸟巢之间的「桥梁」,使得我们能够通过交换鸟巢来达到交换两个鸟巢中所有鸟的目的。

E

图论题有特殊要求,考虑建分层图。

应该想到上面这一句,做法就出来了吧。

实现
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define int long long
using namespace std;

const int N=4e5+5;
int n,m,x;
int dis[N];
bool vis[N];
struct EDGE{
    int v,w;
};
vector<EDGE> G[N];
struct NODE{
    int cur,d;
    bool operator < (const NODE &x) const{
        return d>x.d;
    }
};

void dijkstra(int s){
    priority_queue<NODE> pq;
    memset(dis,0x3f,sizeof dis);
    pq.push({s,0}),dis[s]=0;
    while (!pq.empty()) {
        auto [cur,d]=pq.top();
        pq.pop();
        if (vis[cur]) {
            continue;
        }
        vis[cur]=1;
        for (auto [v,w] : G[cur]) {
            if (dis[v]>dis[cur]+w) {
                dis[v]=dis[cur]+w;
                pq.push({v,dis[v]});
            }
        }
    }
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin>>n>>m>>x;
	for(int i=1,u,v;i<=m;i++){
		cin>>u>>v;
		G[u].push_back({v,1});
		G[v+n].push_back({u+n,1});
	}
	for(int i=1;i<=n;i++){
		G[i].push_back({i+n,x});
		G[i+n].push_back({i,x});
	}
	dijkstra(1);
	cout<<min(dis[n],dis[2*n]);
	return 0;
}

F

考虑第一个要求,显然我们应该将 \(\min\{u_i+d_i\}\) 作为 \(h\)

考虑第二个要求,实际上我们仅需考虑每个数它前面那个数,若那个数 \(+x\) 比当前数小,就减到前面那个数 \(+x\),否则保持原来的数即可,容易证明这样一定是最优的。

因此,这个题告诉我们:有多个要求,逐个考虑

实现
// LUOGU_RID: 208122656
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define int long long
using namespace std;
signed main(){
	int n,x,sum=0,h=1e18,lastu=1e18,lastd=1e18;
	cin>>n>>x;
	for(int i=1,u,d;i<=n;i++)
		cin>>u>>d,sum+=(u+d),lastu=min(lastu+x,u),lastd=min(lastd+x,d),h=min(h,lastu+lastd);
	cout<<sum-n*h;
	return 0;
}

G

不会斯坦纳树。

posted @ 2025-03-15 20:39  _KidA  阅读(17)  评论(0)    收藏  举报