zoukankan      html  css  js  c++  java
  • [tarjan][树上差分] Codeforces 555E Case of Computer Network

    题目描述

    Andrewid the Android is a galaxy-known detective. Now he is preparing a defense against a possible attack by hackers on a major computer network.

    In this network are nn vertices, some pairs of vertices are connected by mm undirected channels. It is planned to transfer qq important messages via this network, the ii -th of which must be sent from vertex s_{i}sito vertex d_{i}di via one or more channels, perhaps through some intermediate vertices.

    To protect against attacks a special algorithm was developed. Unfortunately it can be applied only to the network containing directed channels. Therefore, as new channels can't be created, it was decided for each of the existing undirected channels to enable them to transmit data only in one of the two directions.

    Your task is to determine whether it is possible so to choose the direction for each channel so that each of the qq messages could be successfully transmitted.

    输入输出格式

    输入格式:

    The first line contains three integers nn , mm and qq ( 1<=n,m,q<=2·10^{5}1<=n,m,q<=2105 ) — the number of nodes, channels and important messages.

    Next mm lines contain two integers each, v_{i}vi and u_{i}ui ( 1<=v_{i},u_{i}<=n1<=vi,ui<=n , v_{i}≠u_{i}viui ), that means that between nodes v_{i}vi and u_{i}ui is a channel. Between a pair of nodes can exist more than one channel.

    Next qq lines contain two integers s_{i}si and d_{i}di ( 1<=s_{i},d_{i}<=n1<=si,di<=n , s_{i}≠d_{i}sidi ) — the numbers of the nodes of the source and destination of the corresponding message.

    It is not guaranteed that in it initially possible to transmit all the messages.

    输出格式:

    If a solution exists, print on a single line "Yes" (without the quotes). Otherwise, print "No" (without the quotes).

    输入输出样例

    输入样例#1:
    4 4 2
    1 2
    1 3
    2 3
    3 4
    1 3
    4 2
    
    输出样例#1:
    Yes
    
    输入样例#2:
    3 2 2
    1 2
    3 2
    1 3
    2 1
    
    输出样例#2:
    No
    
    输入样例#3:
    3 3 2
    1 2
    1 2
    3 2
    1 3
    2 1
    
    输出样例#3:
      Yes

    说明

    In the first sample test you can assign directions, for example, as follows: 1→212 , 1→313 , 3→232 , 4→343. Then the path for for the first message will be 1→313 , and for the second one — 4→3→2432 .

    In the third sample test you can assign directions, for example, as follows: 1→212 , 2→121 , 2→323 . Then the path for the first message will be 1→2→3123 , and for the second one — 2→121 .

    题解

    • 对于一个边双连通分量中的点,肯定是让他们能够互相到达是最优的
    • 那么就先把所有边双缩起来,就变成了一棵树的定向问题
    • 对于一棵树的定向,我们可以用树上差分来实现

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 using namespace std;
     5 const int N=200010;
     6 int n,m,q,cnt=1,top,tot,now,tmp,head[N],dfn[N],low[N],stack[N],bel[N],c[N],deep[N],fa[N][20],f[N],g[N];
     7 bool vis[N],ins[N];
     8 struct edge{int to,from;}e[N*4];
     9 void insert(int x,int y)
    10 {
    11     e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt;
    12     e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt;
    13 }
    14 void tarjan(int x,int pre)
    15 {
    16     bel[x]=now,dfn[x]=low[x]=++dfn[0],stack[++top]=x,ins[x]=1;
    17     for (int i=head[x];i;i=e[i].from)
    18         if (i!=(pre^1))
    19             if (!dfn[e[i].to]) tarjan(e[i].to,i),low[x]=min(low[x],low[e[i].to]); else if (ins[e[i].to]) low[x]=min(low[x],dfn[e[i].to]); 
    20     if (dfn[x]==low[x])
    21     {
    22         int k=0; tot++;
    23         while (k!=x) k=stack[top--],c[k]=tot,ins[k]=0;
    24     }
    25 }
    26 void dfs(int x)
    27 {
    28     deep[x]=deep[fa[x][0]]+1;
    29     for (int i=1;i<=18;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
    30     for (int i=head[x];i;i=e[i].from) if (e[i].to!=fa[x][0]) fa[e[i].to][0]=x,dfs(e[i].to);
    31 }
    32 int lca(int x,int y)
    33 {
    34     if (deep[x]<deep[y]) swap(x,y);
    35     for (int i=18;i>=0;i--) if (deep[fa[x][i]]>=deep[y]) x=fa[x][i];
    36     if (x==y) return x;
    37     for (int i=18;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    38     return fa[x][0];
    39 }
    40 void get(int x)
    41 {
    42     vis[x]=1;
    43     for (int i=head[x];i;i=e[i].from) if (!vis[e[i].to]) get(e[i].to),f[x]+=f[e[i].to],g[x]+=g[e[i].to];
    44 }
    45 int main()
    46 {
    47     scanf("%d%d%d",&n,&m,&q);
    48     for (int i=1,x,y;i<=m;i++) scanf("%d%d",&x,&y),insert(x,y);
    49     for (int i=1;i<=n;i++) if (!dfn[i]) now++,tarjan(i,0);
    50     memset(head,0,sizeof(head)),tmp=cnt;
    51     for (int i=2;i<=tmp;i+=2) if (c[e[i].to]!=c[e[i^1].to]) insert(c[e[i].to],c[e[i^1].to]);
    52     for (int i=1;i<=tot;i++) if (!deep[i]) dfs(i);
    53     for (int x,y,LCA;q;q--)
    54     {
    55         scanf("%d%d",&x,&y);
    56         if (bel[x]!=bel[y]) { printf("No"); return 0; }
    57         x=c[x],y=c[y],LCA=lca(x,y),f[x]++,f[LCA]--,g[y]++,g[LCA]--;
    58     }
    59     for (int i=1;i<=tot;i++) if (!vis[i]) get(i);
    60     for (int i=1;i<=tot;i++) if (f[i]&&g[i]) { printf("No"); return 0; }
    61     printf("Yes");
    62 }
  • 相关阅读:
    Ubuntu 16.09下iptables通过raw表实现日志输出和调试
    CentOS 6.9永久设置静态路由表以及路由表常用设置
    Linux下添加静态路由表设置网关出现SIOCADDRT: Network is unreachable的问题分析
    Linux下使用ISC DHCP可以实现动态推送静态路由表
    Linux下使用ping出现destination is unreachable的问题可能性
    树莓派(Debian)系统开启iptables的raw表实现日志输出
    MySQL时间戳与日期互转
    树莓派(Debian)系统设置了静态IP之后还会获取动态IP的问题解决(scope global secondary eth0)
    Linux下同一网段内的IP中两台主机通信不经过路由器(ARP)(转)
    OpenWrt包管理软件opkg的使用(极路由)
  • 原文地址:https://www.cnblogs.com/Comfortable/p/11142937.html
Copyright © 2011-2022 走看看