Luogu4652 CEOI2017 One-Way Streets 树上差分
Posted itst
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu4652 CEOI2017 One-Way Streets 树上差分相关的知识,希望对你有一定的参考价值。
题意:给出$N$个点、$M$条无向边的图,现在你需要给它定向,并满足$Q$个条件:每个条件形如$(x_i,y_i)$,表示定向之后需要存在路径从$x_i$走向$y_i$。问每条边是否都有唯一定向方式。$N,M,Q leq 10^5$
图论总是涉及的算法不难,但是就是脑子生锈想不出来
可以知道一个边双联通分量里面的所有边的方向都是一定不能确定的,因为如果存在一种方式满足所有条件,将这个边双联通分量里的所有边取反之后也一定满足条件。所以我们只需要考虑割边。
不妨在原图中找到一棵树,这棵树上必定包含所有的割边。通过差分将非割边打上标记,我们就可以通过在新的树上求$LCA$加上差分对所有边向上还是向下打好标记,最后$dfs$求出答案即可。
实际上还可以并查集,但是并查集写炸了qwq
注意重边,还要注意图不连通的情况
1 #include<bits/stdc++.h>
2 using namespace std;
3
4 inline int read(){
5 int a = 0;
6 bool f = 0;
7 char c = getchar();
8 while(c != EOF && !isdigit(c)){
9 if(c == ‘-‘)
10 f = 1;
11 c = getchar();
12 }
13 while(c != EOF && isdigit(c)){
14 a = (a << 3) + (a << 1) + (c ^ ‘0‘);
15 c = getchar();
16 }
17 return f ? -a : a;
18 }
19
20 const int MAXN = 100010;
21 struct Edge{
22 int end , upEd;
23 }Ed[MAXN << 1];
24 int N , M , cntEd = 1 , head[MAXN] , dep[MAXN] , up[MAXN] , down[MAXN] , can[MAXN] , jump[MAXN][20];
25 char ans[MAXN];
26 bool vis[MAXN];
27
28 inline void addEd(int a , int b){
29 Ed[++cntEd].end = b;
30 Ed[cntEd].upEd = head[a];
31 head[a] = cntEd;
32 }
33
34 void dfs(int x , int fa){
35 jump[x][0] = fa;
36 dep[x] = dep[fa] + 1;
37 for(int i = 1 ; i <= 19 ; i++)
38 jump[x][i] = jump[jump[x][i - 1]][i - 1];
39 for(int i = head[x] ; i ; i = Ed[i].upEd)
40 if(!dep[Ed[i].end])
41 dfs(Ed[i].end , x);
42 else
43 if(dep[Ed[i].end] > dep[x]){
44 can[Ed[i].end]++;
45 can[x]--;
46 }
47 }
48
49 void Dfs(int x){
50 vis[x] = 1;
51 for(int i = head[x] ; i ; i = Ed[i].upEd)
52 if(dep[Ed[i].end] == dep[x] + 1 && !vis[Ed[i].end]){//不加vis判断会炸!!!
53 Dfs(Ed[i].end);
54 if(can[Ed[i].end] == 0)
55 if((i & 1) && up[Ed[i].end] || !(i & 1) && down[Ed[i].end])
56 ans[i >> 1] = ‘R‘;
57 else
58 if(!(i & 1) && up[Ed[i].end] || (i & 1) && down[Ed[i].end])
59 ans[i >> 1] = ‘L‘;
60 up[x] += up[Ed[i].end];
61 down[x] += down[Ed[i].end];
62 can[x] += can[Ed[i].end];
63 }
64 }
65
66 inline int jumpToLCA(int x , int y){
67 if(dep[x] < dep[y])
68 swap(x , y);
69 for(int i = 19 ; i >= 0 ; i--)
70 if(dep[x] - (1 << i) >= dep[y])
71 x = jump[x][i];
72 if(x == y)
73 return x;
74 for(int i = 19 ; i >= 0 ; i--)
75 if(jump[x][i] != jump[y][i]){
76 x = jump[x][i];
77 y = jump[y][i];
78 }
79 return jump[x][0];
80 }
81
82 int main(){
83 #ifdef LG
84 freopen("4652.in" , "r" , stdin);
85 freopen("4652.out" , "w" , stdout);
86 #endif
87 N = read();
88 M = read();
89 for(int i = 1 ; i <= M ; i++){
90 int a = read() , b = read();
91 addEd(a , b);
92 addEd(b , a);
93 }
94 for(int i = 1 ; i <= N ; i++)
95 if(!dep[i])
96 dfs(i , 0);
97 for(int Q = read() ; Q ; Q--){
98 int a = read() , b = read() , t = jumpToLCA(a , b);
99 up[a]++;
100 up[t]--;
101 down[t]--;
102 down[b]++;
103 }
104 memset(ans , ‘B‘ , sizeof(ans));
105 for(int i = 1 ; i <= N ; i++)
106 if(!vis[i])
107 Dfs(i);
108 for(int i = 1 ; i <= M ; i++)
109 cout << ans[i];
110 return 0;
111 }
以上是关于Luogu4652 CEOI2017 One-Way Streets 树上差分的主要内容,如果未能解决你的问题,请参考以下文章
Luogu P4654 [CEOI2017]Mousetrap
Luogu P5999 [CEOI2016]kangaroo
Luogu4697 CEOI2011 Balloons 单调栈