1876. Basic Graph Problem
Constraints
Time Limit: 5 secs, Memory Limit: 32 MB
Description
Graph theory is an interesting science and applied in many areas. We can always construct a graph model when we have a complicated problem to consider. With the model, we can simplify the problem and know what and how we should do. There are many well-known problems in graph theory, such as Hamilton Cycle, traveling salesman problem, postman problem. etc. Oh, god, all of them seems too difficult to think about for most college students. Don’t worry, in this problem we just need to consider a basic problem: the connectivity of a graph (Aha, is it easy enough for you ^_^)
We denoted a graph G as (V, E),V is the set of all the nodes in G, and N=|V| is the number of nodes in G.E is the set of all the edges in G, An edge can be denoted by two nodes (a1,a2),that means node a1 and node a2 are connected by one edge.
Now the problem is: Given a graph G, could you tell whether any of two nodes are connected (both directed and undirected).
Input
There are many test data in the input, a test data is defined as follow:
The first line of test data contains an integer n (1<=n<=100000), the number of nodes of G
It’s followed by n different integers, one integer Ai (1<=Ai<=n, 1<=i<=n)per line. (We use integer 1 to n to denote the nodes of G)
n
A1 (1<= A1<=n)
A2 (1<= A2<=n)
…
An (1<= An<=n)
The next line contains an integer m (1<=m<=500000).Following this are m lines, describing the edges of G. Each line contains two integers Si and Ei (1<=Si<=n,1<=Ei<=n,
,Si<Ei 1<=i<=m)
m
S1 E1 (1<=S1<=n,1<=E1<=n,S1<E1)
S2 E2 (1<=S2<=n,1<=E2<=n,S2<E2)
….
Sm Em (1<=Sm<=n,1<=Em<=n,Sm<Em)
For each i (1<=i<=m), you should find the minimal number Amin =min{ As1, As2…. Ae1,} and maximal number Amax =max{ As1, As2…. Ae1} from the n different integers inputted before in the range of [Si, Ei], and then we can get an information that Amin and Amax are connected by one edge directly in G
The next line contains an integer k (1<=k<=100000), followed by k queries
K
u1 v1 (1<=u1<=n, 1<= v1<=n)
u2 v2 (1<=u2<=n, 1<= v2<=n)
….
uk vk (1<=uk<=n, 1<= vk<=n)
For each i (1<=i<=k) , you should answer whether node ui and node vi is connected (both directed and undirected).
You can assume that any node is always connected by itself, and there may be many edges between any two nodes.
Input is ended by EOF.
Output
For each test data, first display the case number (starts with 1 and increases sequentially), and then you should output k lines. For each line , you should output “YES “on the ith line if node ui and node vi is connected (both directed and undirected)in the input ,or “NO” otherwise. Output should be separated by one blank line.
Sample Input
3 3 1 2 1 1 2 5 1 3 3 1 2 2 1 2 2 3 5 2 3 5 4 1 3 2 3 3 5 1 2 3 3 1 5 1 4 5
Sample Output
CASE 1 YES YES YES NO NO CASE 2 YES YES NO
Hint
Here is the explanation of the last sample input. There are 5 nodes and the input order is 2 3 5 4 1.There are 3 edges: Since the 2 nd and the 3th number in the input is {3 , 5},so the minimal number is 3 and maximal number is 5,and we know that node 3 and node 5 is connected directed. Similarly, the 3th ,4 th and 5 th number in the input is {5, 4, 1}, the minimal number is 1 and the maximal number is 5. That means node 1 and node 5 is also connected by a edge. Likewise we can get the information that node 2 is connected to node 3 from input. So that node 1 and node 3 are connected undirected, node5 and node1 are connected directed, node5 and node4 are not connected.
// Problem#: 1876
// Submission#: 3589915
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <stdio.h>
const int MAXV = 101100;
int n, m, k;
struct node {
int min, max;
};
node arr[MAXV];
int input[MAXV];
int c;
int parent[MAXV];
void buildtree(int s, int e,int & maximal, int & minimal) {
if (e - s + 1 <= 0) {
maximal = minimal = -1;
return;
}
if (e - s + 1 == 1) {
maximal = minimal = input[e];
return;
}
if (e - s + 1 == 2) {
maximal = input[s] > input[e] ? input[s] : input[e];
minimal = input[s] > input[e] ? input[e] : input[s];
return;
}
int temp = (s + e) / 2;
arr[temp].max = input[temp];
arr[temp].min = input[temp];
int i, j;
buildtree(s, temp - 1, i, j);
if (i >= 0 && j >= 0) {
if (i > arr[temp].max) arr[temp].max = i;
if (j < arr[temp].min) arr[temp].min = j;
}
buildtree(temp + 1, e, i, j);
if (i >= 0 && j >= 0) {
if (i > arr[temp].max) arr[temp].max = i;
if (j < arr[temp].min) arr[temp].min = j;
}
maximal = arr[temp].max;
minimal = arr[temp].min;
}
void init() {
int i, j;
buildtree(0, n - 1, i, j);
}
void searchtree(int s, int e, int & maximal, int & minimal, int u, int v) {
if (e - s + 1 <= 0) {
maximal = minimal = -1;
return;
}
if (s == u && v == e) {
if (e - s + 1 <= 0) {
maximal = minimal = -1;
return;
}
if (e - s + 1 == 1) {
maximal = minimal = input[e];
return;
}
if (e - s + 1 == 2) {
maximal = input[s] > input[e] ? input[s] : input[e];
minimal = input[s] > input[e] ? input[e] : input[s];
return;
}
maximal = arr[(s + e) / 2].max;
minimal = arr[(s + e) / 2].min;
return;
}
int temp = (s + e) / 2;
int i, j;
if (u <= temp && temp <= v) {
maximal = input[temp];
minimal = input[temp];
if (u <= temp - 1) {
searchtree(s, temp - 1, i, j, u, temp - 1);
if (i > maximal) maximal = i;
if (j >= 0 && j < minimal) minimal = j;
}
if (v >= temp + 1) {
searchtree(temp + 1, e, i, j, temp + 1, v);
if (i > maximal) maximal = i;
if (j >= 0 && j < minimal) minimal = j;
}
return;
}
if (u > temp) {
searchtree(temp + 1, e, maximal, minimal, u, v);
return;
}
searchtree(s, temp - 1, maximal, minimal, u, v);
}
int find(int a) {
int i = a;
while (parent[a] >= 0) a = parent[a];
while (i != a) {
int temp = parent[i];
parent[i] = a;
i = temp;
}
return a;
}
void unionset(int a, int b) {
int i = find(a), j = find(b);
if (i == j) return;
if (i < j) {
parent[j] = i;
parent[i]--;
} else {
parent[i] = j;
parent[j]--;
}
}
void process() {
int i;
if (c != 0) printf("\n");
c++;
printf("CASE %d\n", c);
for (i = 0; i < n; i++) {
scanf("%d", input + i);
input[i]--;
parent[i] = -1;
}
init();
scanf("%d", &m);
int u, v;
for (i = 0; i < m; i++) {
scanf("%d%d", &u, &v);
u--;
v--;
searchtree(0, n - 1, u, v, u, v);
unionset(u, v);
}
scanf("%d", &k);
for (i = 0; i < k; i++) {
scanf("%d%d", &u, &v);
u--;
v--;
if (find(u) == find(v)) printf("YES\n");
else printf("NO\n");
}
}
int main() {
while (scanf("%d", &n) != EOF) process();
return 0;
}