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 }
原文地址:https://www.cnblogs.com/Itst/p/9859097.html