D - Pigeon Swap Time Limit: 2 sec / Memory Limit:...
创建于:2025年3月1日
创建于:2025年3月1日
D - Pigeon Swap
Time Limit: 2 sec / Memory Limit: 1024 MB
Score :
350 points
Problem Statement
There are
N pigeons labeled 1,2,…,N and N nests labeled
1,2,…,N.
Initially, pigeon
i (1≤i≤N) is in nest
i.
You will perform
Q operations on these pigeons.
There are three types of operations:
Type
1: You are given integers a and b (1≤a≤N,1≤b≤N). Take pigeon a out of its current nest and move it to nest
b.
Type
2: You are given integers a and b (1≤a<b≤N). Move all pigeons in nest a to nest b, and move all pigeons in nest b to nest
a. These two moves happen simultaneously.
Type
3: You are given an integer a (1≤a≤N). Pigeon
a reports the label of the nest it is currently in.
Print the result of each Type
3 operation in the order the operations are given.
Constraints
1≤N≤106
1≤Q≤3×105
Every operation is of Type
1, 2, or
3.
All operations are valid according to the problem statement.
There is at least one Type
text3 operation. All input values are integers.
Input
The input is given from Standard Input in the following format:
N
Q
op1
op2
⋮
opQ
Here,
opi on the line i+1 represents the
i-th operation in one of the following formats.
If the
i-th operation is of Type 1,
opi is in the following format:
1
a
b
This corresponds to a Type
1 operation with the given integers being a and
b.
If the
i-th operation is of Type 2,
opi is in the following format:
2
a
b
This corresponds to a Type
2 operation with the given integers being a and
b.
If the
i-th operation is of Type 3,
opi is in the following format:
3
a
This corresponds to a Type
3 operation with the given integer being
a.
Output
Let the number of Type
3 operations be q. Print q lines. The i-th line (1≤i≤q) should contain the nest number reported in the i-th Type
3 operation.
Sample Input 1
6 8
1 2 4
1 3 6
3 2
2 4 5
3 2
1 4 2
3 4
3 2
Sample Output 1
4
5
2
5
In the operations given, the pigeons move as shown in the figure below:
The nest numbers to be reported for the Type
3 operations are
4,5,2,5. Print 4, 5, 2, 5 on separate lines.
Sample Input 2
1 2
1 1 1
3 1
Sample Output 2
1
The destination nest of a Type
1 operation may be the same as the nest the pigeon is currently in.
Sample Input 3
30 15
3 3
2 8 30
2 12 15
2 2 17
1 19 1
2 7 30
3 12
3 8
2 25 26
1 13 10
1 16 10
2 16 29
2 1 21
2 6 11
1 21 8
Sample Output 3
3
15
7
E - Flip Edge
Time Limit: 2 sec / Memory Limit: 1024 MB
Score :
425 points
Problem Statement
You are given a directed graph with
N vertices and M edges. The i-th edge (1≤i≤M) is a directed edge from vertex ui to vertex
vi.
Initially, you are at vertex
N:
textPerform one of the two operations below: Move along a directed edge from your current vertex. This incurs a cost of
More precisely, if you are at vertex v, choose a vertex u such that there is a directed edge from v to u, and move to vertex
u.
Reverse the direction of all edges. This incurs a cost of
X. More precisely, if and only if there was a directed edge from v to u immediately before this operation, there is a directed edge from u to
v immediately after this operation.
It is guaranteed that, for the given graph, you can reach vertex
N from vertex
1 by repeating these operations.
Find the minimum total cost required to reach vertex
N.
Constraints
2≤N≤2×105
1≤M≤2×105
1≤X≤109
1≤ui≤N (1≤i≤M)
1≤vi≤N (1≤i≤M)
For the given graph, it is guaranteed that you can reach vertex
N from vertex
text1 by the operations described. All input values are integers.
Input
The input is given from Standard Input in the following format:
N
M
X
u1
v1
u2
v2
⋮
uM
vM
Output
Print the minimum total cost required to reach vertex
N.
Sample Input 1
5 6 5
1 2
2 4
3 1
3 5
4 3
5 2
Sample Output 1
4
The given graph looks like this:
You can reach vertex
5 with a total cost of
4 by doing the following:
Move to vertex
2 at a cost of
1.
Move to vertex
4 at a cost of
1.
Move to vertex
3 at a cost of
1.
Move to vertex
5 at a cost of
1.
It is impossible to reach vertex
5 with a total cost of
3 or less, so print 4.
Sample Input 2
5 6 1
1 2
2 4
3 1
3 5
4 3
5 2
Sample Output 2
3
The graph is the same as in Sample 1, but the cost to reverse edges is different.
You can reach vertex 5 with a total cost of
3 as follows:
Move to vertex
2 at a cost of
1.
Reverse all edges at a cost of
1.
Move to vertex
5 at a cost of
1.
It is impossible to reach vertex
5 with a total cost of
2 or less, so print 3.
Sample Input 3
8 7 613566756
2 1
2 3
4 3
4 5
6 5
6 7
8 7
Sample Output 3
4294967299
Note that the answer may exceed the
32-bit integer range.
Sample Input 4
20 13 5
1 3
14 18
18 17
12 19
3 5
4 6
13 9
8 5
14 2
20 18
8 14
4 9
14 8
Sample Output 4
21
Solution Sketch for D – Pigeon Swap
We have pigeons (numbered to ) and nests (also numbered to ). Initially, pigeon sits in nest . There are three types of operations:
Type 1 :
Move pigeon from its current nest to nest .
Type 2 :
Swap all pigeons in nest with all pigeons in nest . These two moves happen simultaneously.
Type 3 :
Query which nest pigeon is currently in.
We must process operations in total, possibly up to , with up to . The main challenge is that a direct or naïve swapping of entire sets (for Type 2) could be very large if done pigeon-by-pigeon. We need an or at least amortized approach per operation.
Instead of literally storing which pigeons are in each nest and swapping them one by one, we use an indirection:
containers
numbered to .Initially,
physical_label[i] = i
.So pigeon being “in nest ” is encoded as “pigeon is in container , and container has physical nest label .”
We also maintain a quick lookup of which container currently corresponds to which physical nest number. Call it container_of_label[]
:
container_of_label[i] = i
for all .Hence:
physical_label[c]
.Type 3 (Query):
To answer “Which nest is pigeon in?” we do:
cppint c = pigeon_container[a]; // container of pigeon a int answer = physical_label[c]; // the current physical nest label // print `answer`
Type 2 (Swap entire nests and ):
c1
and c2
such that
\text{physical_label}[c1] = a,\quad \text{physical_label}[c2] = b.
This instantly swaps all pigeons that were “physically in nest ” with those “physically in nest ,” because we never moved any pigeons around; we only swapped which physical labels (i.e. nest numbers) belong to which container.
Type 1 (Move pigeon to nest ):
old_c = pigeon_container[a]
.new_c = container_of_label[b]
.new_c
. In code, that can simply be:
cpppigeon_container[a] = new_c;
Since each of these steps is (given direct array lookups), we can handle up to operations efficiently, and we only store a few arrays of size (and size is up to , which is still acceptable within 1GB memory limit).
Below is a condensed form of how one might implement it:
cpp#include <bits/stdc++.h> using namespace std; static const int MAXN = 1000000; // Arrays (1-indexed for convenience if problem is 1-indexed): // pigeon_container[a] = which container pigeon a currently belongs to // physical_label[c] = the physical nest label that container c represents // container_of_label[L] = which container currently has physical label L int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); int N, Q; cin >> N >> Q; vector<int> pigeon_container(N+1), physical_label(N+1), container_of_label(N+1); // Initialize for(int i = 1; i <= N; i++){ pigeon_container[i] = i; // Pigeon i initially in container i physical_label[i] = i; // Container i initially has label i container_of_label[i]= i; // Nest label i is held by container i } while(Q--){ int op; cin >> op; if(op == 1){ int a,b; cin >> a >> b; // move pigeon a to nest b int old_c = pigeon_container[a]; int new_c = container_of_label[b]; // put pigeon a into container new_c pigeon_container[a] = new_c; } else if(op == 2){ int a,b; cin >> a >> b; // swap the entire contents of nest a and b int c1 = container_of_label[a]; int c2 = container_of_label[b]; // swap physical labels int tmp = physical_label[c1]; physical_label[c1] = physical_label[c2]; physical_label[c2] = tmp; // update container_of_label container_of_label[ physical_label[c1] ] = c1; container_of_label[ physical_label[c2] ] = c2; } else { // query int a; cin >> a; int c = pigeon_container[a]; int ans = physical_label[c]; cout << ans << "\n"; } } return 0; }
All operations work in time. For large , this approach stays efficient and fits memory constraints.
We have a directed graph of vertices and edges. You start at vertex . You want to reach vertex . Two types of operations are possible:
Move along an existing directed edge at a cost of .
Reverse all edges in the entire graph at a cost of .
We want the minimum total cost to go from vertex to vertex . Note that we can do the reversal any number of times, each time paying cost .
Since edges can be either in the original orientation or in the reversed orientation, define the orientation bit as or :
A flip operation toggles between orientation and orientation .
Hence we consider an expanded graph of size “states”:
Move along a directed edge (cost = 1):
Flip orientation (cost = ):
We want the shortest path from to or . Once you reach vertex in either orientation, you are done (the problem states we only care about arriving at ).
Since each edge has cost either or , and can be as large as , we use a normal Dijkstra (with a priority queue), not a 0–1 BFS. The graph has:
The number of edges is about for the “move” edges (forward and reversed) plus for the “flip” edges, which is acceptable for and .
Then we run Dijkstra from . Let dist[v][orient]
= minimum cost to reach state . Initialize dist[1][0] = 0
, all others ∞
. Use a priority queue (min-heap).
At the end, the answer is
adjF[v]
for forward edges (from to its neighbors).adjR[v]
for reversed edges (if the original has , then in adjR[u]
we store ).But more commonly, we just keep two separate adjacency lists for orientation=0 and orientation=1 logic, then handle flipping in Dijkstra code.cpp// We'll store edges of the form: (to, cost). vector<vector<pair<int, long long>>> graph(2*N + 1);
dist[v][0]
and dist[v][1]
.(current_cost, vertex, orientation)
.min(dist[N][0], dist[N][1])
.Since , a standard Dijkstra with (roughly) is usually efficient enough in 2 seconds.
long long
in C++ or long
in Java/Python).These methods handle the given constraints efficiently and are standard approaches for such “swap-all” or “flip-all” style problems.