D - Pigeon Swap Time Limit: 2 sec / Memory Limit:...

创建于:2025年3月1日

使用 O1 回答 Chat01

问题

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

text
3 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

  1. You want to repeat the following operations until you reach vertex

N:

text
Perform one of the two operations below: Move along a directed edge from your current vertex. This incurs a cost of
  1. 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

text
1 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

思考

Addressing challenges

I’m working through two AtCoder problems: D - Pigeon Swap and E - Flip Edge. The first needs an efficient data structure to manage pigeon nests and Q operations due to constraints.

Managing pigeon nests

I’m examining three types of operations: relocating a single pigeon, swapping all pigeons between nests, and querying a pigeon’s nest. Naive solutions are impractical due to constraints.

Utilizing logical labels

I’m thinking through a "nest representative" approach, where each pigeon has a logical nest label. Swapping nests involves exchanging these labels, maintaining efficient operations.

Mapping relationships

I’m exploring data structures to map each pigeon to its current nest ID and efficiently swap nest contents, ensuring consistent label tracking across various operations.

Simplifying swaps

I’m thinking of using a nested array to link pigeon IDs to nest labels, ensuring efficient swaps. This method minimizes time complexity while maintaining accurate tracking of each pigeon’s location.

Mapping pigeons to nests

I'm focusing on associating each pigeon with a logical nest using an array. This allows efficient updating and querying by referring to the logical nest of each pigeon.

Arranging pigeon movements

I’m thinking through a strategy to manage pigeon movements efficiently. By using a nest_location_inverse array, each pigeon can quickly find its new logical nest, reducing time complexity.

Pairing pigeons with nests

Hmm, I’m thinking about efficiently swapping nests using Union-Find. Each pigeon’s container identifies its physical nest. This method ensures quick operations and streamlined organization.

Mixing pigeon habits

To swap containers efficiently, I’m considering pairing pigeon IDs with nest labels, ensuring a quick switch of contents from two containers. This method maintains data integrity and enhances performance.

Organizing the swap

I'm piecing together how to streamline swaps by focusing on container labels. This approach keeps operations quick and ensures accurate pigeon tracking.

Figuring out membership

I'm mapping out container switches by focusing on pigeon memberships. Using an array to pinpoint container locations and linked lists for managing memberships optimizes efficiency, even with large numbers.

Streamlining operations

I’m thinking about a solution using a linked list for pigeon membership and an array for container labels. This ensures O(1) operations for adding, removing, and identifying pigeons efficiently.

Establishing pigeon organization

I'm streamlining operations with an array for physical labels, double linked lists for memberships, and precise pigeon relocation processes. This helps track pigeon properties effectively.

Considering storage options

I'm thinking through more memory-efficient strategies to manage 1 million pigeons and containers. This involves rethinking linked list use and focusing on physical label swaps to cut down on memory usage.

Streamlining membership tracking

By simplifying pigeon moves to container swaps, membership removal becomes unnecessary. This cuts down on complexity and focuses on managing pigeon_container mappings effectively.

Tracking pigeon locations

I’m leaving out container tracking and only keeping an array for pigeons. This makes me think about how the physical labels of nests just swap, not their actual containers.

Revisiting pigeon organization

OK, I’m concluding that each pigeon is tied to a container by pointers, not by a membership list. This ensures efficient pigeon handling with straightforward physical label swaps.

Selecting optimal strategies

Focusing on flipping edges in a directed graph, I’m piecing together efficient paths and costs. BFS or D'Johnson approach are promising, especially for large costs.

Balancing edge direction and cost

I’m mapping this out with graph states (vertex, orientation): 0 for original, 1 for reversed. Flips cost X, and I’m aligning paths with orientation-based costs.

Finding a cost-effective path

Let's think this through: using the Dijkstra algorithm and a priority queue to minimize total cost. This approach efficiently handles the complexity of edge costs and orientations.

Crafting the adjacency

I'm filling out the adjacency lists: original graph's orientation 0, transpose for orientation 1. Connections between (v,0) to (v,1) with cost X are also included.

Reasoned for 1m 11s

回答

Solution Sketch for D – Pigeon Swap

We have NN pigeons (numbered 11 to NN) and NN nests (also numbered 11 to NN). Initially, pigeon ii sits in nest ii. There are three types of operations:

  1. Type 1 (1  a  b)(1\; a\; b):
    Move pigeon aa from its current nest to nest bb.

  2. Type 2 (2  a  b)(2\; a\; b):
    Swap all pigeons in nest aa with all pigeons in nest bb. These two moves happen simultaneously.

  3. Type 3 (3  a)(3\; a):
    Query which nest pigeon aa is currently in.

We must process QQ operations in total, possibly up to 3×1053 \times 10^5, with NN up to 10610^6. 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 O(1)O(1) or at least amortized O(logN)O(\log N) approach per operation.


Key Idea: “Container” (or “Bucket”) Representation

Instead of literally storing which pigeons are in each nest and swapping them one by one, we use an indirection:

  • We maintain containers numbered 11 to NN.
  • Each container has a “current physical nest label.”
  • Each pigeon points to exactly one container (saying: “this pigeon is in container cc”).

Initially,

  • Container ii has physical_label[i] = i.
  • Pigeon ii sits in container ii.

So pigeon ii being “in nest ii” is encoded as “pigeon ii is in container ii, and container ii has physical nest label ii.”

We also maintain a quick lookup of which container currently corresponds to which physical nest number. Call it container_of_label[]:

  • At the start, container_of_label[i] = i for all ii.

Hence:

  • If pigeon pp is in container cc, then the actual nest that pigeon pp occupies is physical_label[c].

Operations

  1. Type 3 (3  a)(3\; a) (Query):
    To answer “Which nest is pigeon aa in?” we do:

    cpp
    int c = pigeon_container[a]; // container of pigeon a int answer = physical_label[c]; // the current physical nest label // print `answer`
  2. Type 2 (2  a  b)(2\; a\; b) (Swap entire nests aa and bb):

    • Find the containers c1 and c2 such that \text{physical_label}[c1] = a,\quad \text{physical_label}[c2] = b.
    • Swap the two containers’ nest labels: \text{swap}\bigl(\text{physical_label}[c1],\ \text{physical_label}[c2]\bigr).
    • Update our reverse lookup so that \text{container_of_label}[\text{physical_label}[c1]] = c1,\quad \text{container_of_label}[\text{physical_label}[c2]] = c2.

    This instantly swaps all pigeons that were “physically in nest aa” with those “physically in nest bb,” because we never moved any pigeons around; we only swapped which physical labels (i.e. nest numbers) belong to which container.

  3. Type 1 (1  a  b)(1\; a\; b) (Move pigeon aa to nest bb):

    • Let old_c = pigeon_container[a].
    • We want to move pigeon aa to the nest whose physical label is bb. Find that container: new_c = container_of_label[b].
    • Remove pigeon aa from its old container and place it in new_c. In code, that can simply be:
      cpp
      pigeon_container[a] = new_c;
    • No other pigeons need to move. This is an O(1)O(1) action.

Since each of these steps is O(1)O(1) (given direct array lookups), we can handle up to 3×1053 \times 10^5 operations efficiently, and we only store a few arrays of size NN (and size NN is up to 10610^6, which is still acceptable within 1GB memory limit).


Pseudocode

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 O(1)O(1) time. For large N,QN,Q, this approach stays efficient and fits memory constraints.


Solution Sketch for E – Flip Edge

We have a directed graph of NN vertices and MM edges. You start at vertex 11. You want to reach vertex NN. Two types of operations are possible:

  1. Move along an existing directed edge at a cost of 11.

    • If you are at vertex vv, you can move to uu if there is an edge vuv \to u.
  2. Reverse all edges in the entire graph at a cost of XX.

    • Immediately after reversing, every edge vuv \to u becomes uvu \to v.

We want the minimum total cost to go from vertex 11 to vertex NN. Note that we can do the reversal any number of times, each time paying cost XX.


Standard Trick: “State” = (Vertex, Orientation)

Since edges can be either in the original orientation or in the reversed orientation, define the orientation bit as 00 or 11:

  • Orientation 00 means “the graph is in its original direction.”
  • Orientation 11 means “the graph has been reversed from the original.”

A flip operation toggles between orientation 00 and orientation 11.

Hence we consider an expanded graph of size 2N2N “states”:

  • State (v,0)(v, 0): You are at vertex vv with the graph in orientation 00.
  • State (v,1)(v, 1): You are at vertex vv with the graph in orientation 11.

Transitions

  1. Move along a directed edge (cost = 1):

    • If orientation = 0, from (v,0)(v, 0) you can move to (u,0)(u, 0) if there is an original edge vuv \to u.
    • If orientation = 1, from (v,1)(v, 1) you can move to (u,1)(u, 1) if there is an original edge uvu \to v (because in orientation 1, edges are reversed).
  2. Flip orientation (cost = XX):

    • From (v,0)(v, 0) you can go to (v,1)(v, 1) at cost XX.
    • From (v,1)(v, 1) you can go to (v,0)(v, 0) at cost XX.

We want the shortest path from (1,0)(1, 0) to (N,0)(N, 0) or (N,1)(N, 1). Once you reach vertex NN in either orientation, you are done (the problem states we only care about arriving at NN).


Dijkstra’s Algorithm on 2-Layer Graph

Since each edge has cost either 11 or XX, and XX can be as large as 10910^9, we use a normal Dijkstra (with a priority queue), not a 0–1 BFS. The graph has:

  • Vertices: (v,0)(v, 0) and (v,1)(v, 1) for v=1,2,,Nv = 1,2,\dots, N. So 2N2N states in total.
  • Edges:
    1. For each original directed edge (vu)(v \to u), we add:
      • (v,0)(u,0)(v,0) \to (u,0) with cost 1.
      • (u,1)(v,1)(u,1) \to (v,1) with cost 1. (Because in orientation 1, an edge vuv \to u is reversed to uvu \to v.)
    2. For each vertex vv:
      • (v,0)(v,1)(v,0) \leftrightarrow (v,1) with cost XX.

The number of edges is about 2M2M for the “move” edges (forward and reversed) plus 2N2N for the “flip” edges, which is acceptable for M2×105M \le 2\times 10^5 and N2×105N \le 2\times 10^5.

Then we run Dijkstra from (1,0)(1, 0). Let dist[v][orient] = minimum cost to reach state (v,orient)(v, orient). Initialize dist[1][0] = 0, all others &infin;. Use a priority queue (min-heap).

At the end, the answer is

min(dist[N][0], dist[N][1]). \min\bigl(\text{dist}[N][0],\ \text{dist}[N][1]\bigr).

Implementation Outline

  1. Read N,M,XN, M, X.
  2. Build two adjacency lists:
    • adjF[v] for forward edges (from vv to its neighbors).
    • adjR[v] for reversed edges (if the original has vuv \to u, then in adjR[u] we store vv).
  3. Use a structure like:
    cpp
    // We'll store edges of the form: (to, cost). vector<vector<pair<int, long long>>> graph(2*N + 1);
    But more commonly, we just keep two separate adjacency lists for orientation=0 and orientation=1 logic, then handle flipping in Dijkstra code.
  4. Run Dijkstra on the 2*N state-graph:
    • Distances array: dist[v][0] and dist[v][1].
    • Priority queue states: (current_cost, vertex, orientation).
    • Relax edges according to the rules above.
  5. Print min(dist[N][0], dist[N][1]).

Since N,M2×105N, M \le 2\times 10^5, a standard Dijkstra with O((N+M)logN)O((N + M)\log N) (roughly) is usually efficient enough in 2 seconds.


Edge Cases

  • XX can be huge (109\le 10^9) or smaller than 1.
  • Possibly it is faster never to flip (if XX is huge) or to flip once or multiple times. The algorithm automatically finds the best approach.
  • The answer might exceed 32-bit integer range, so store distances in a 64-bit type (long long in C++ or long in Java/Python).

Final Remarks

  • D – Pigeon Swap: Use containers + swapping labels in O(1)O(1).
  • E – Flip Edge: Model as a 2-layer (orientation-0, orientation-1) graph and run Dijkstra.

These methods handle the given constraints efficiently and are standard approaches for such “swap-all” or “flip-all” style problems.

分享这个问答