zoukankan      html  css  js  c++  java
  • BZOJ3331 [BeiJing2013]压力[圆方树+树上差分]

    圆方树新技能get。具体笔记见图连通性问题学习笔记。

    这题求无向图的必经点,这个是一个固定套路:首先,一张连通的无向图中,每对点双和点双之间是以一个且仅一个割点连接起来的(如果超过一个就不能是割点了),那么,在一个点双内部,从出发点开始,要走到另外一个点双中,这个中间的割点就是一条必经之路(没有其他路可以绕,否则这就有一个环了),所以,路上所有割点都是必经点,而点双内部走的话,由点双的定义,是至少有两条点不相交的路径的(当然两个点的点双的话直接没有中间点),所以中间非割点是可经而不是必经的。

    所以,构建圆方树,起始点和终止点构成的路径上所有圆点就是答案。然后,依题意做树上差分即可。

    为什么我线性求lca还跑不过log的啊。。

    圆方树构建的code大致是模仿zsy写的。。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define mst(x) memset(x,0,sizeof x)
     8 #define dbg(x) cerr << #x << " = " << x <<endl
     9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
    10 using namespace std;
    11 typedef long long ll;
    12 typedef double db;
    13 typedef pair<int,int> pii;
    14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    19 template<typename T>inline T read(T&x){
    20     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    21     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    22 }
    23 const int N=1e5+7;
    24 struct thxorz{
    25     int to[N<<2],nxt[N<<2],head[N<<1],tot;
    26     inline void add(int x,int y){
    27         to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
    28         to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
    29     }
    30 }G1,G2,Q;
    31 int n,m,q;
    32 int tag[N<<1],fa[N<<1],anc[N<<1],vis[N<<1];
    33 int Find(int x){return anc[x]==x?x:anc[x]=Find(anc[x]);}
    34 #define y G2.to[j]
    35 #define qy Q.to[j]
    36 void tarjan_lca(int x,int fat){
    37     anc[x]=x;fa[x]=fat;
    38     for(register int j=G2.head[x];j;j=G2.nxt[j])if(fat^y)tarjan_lca(y,x),anc[y]=x;
    39     vis[x]=1;int tmp;
    40     for(register int j=Q.head[x];j;j=Q.nxt[j])if(vis[qy])tmp=Find(qy),--tag[tmp],--tag[fa[tmp]];
    41 }
    42 void dfs(int x){for(register int j=G2.head[x];j;j=G2.nxt[j])if(fa[x]^y)dfs(y),tag[x]+=tag[y];}
    43 #undef y
    44 #undef qy
    45 #define y G1.to[j]
    46 int dfn[N],low[N],stk[N],Top,tim,cnt;
    47 void tarjan(int x){//promise:connected,without vertexes isolated.
    48     dfn[x]=low[x]=++tim;stk[++Top]=x;
    49     for(register int j=G1.head[x];j;j=G1.nxt[j]){
    50         if(!dfn[y]){//We needn't get the cut-vertexes,and cut-vertexes have nothing to do with v-DCCs.
    51             tarjan(y),MIN(low[x],low[y]);
    52             if(dfn[x]==low[y]){
    53                 int tmp;++cnt;
    54                 do tmp=stk[Top--],G2.add(tmp,cnt);while(tmp^y);
    55                 G2.add(x,cnt);
    56             }
    57         }
    58         else MIN(low[x],dfn[y]);
    59     }
    60 }
    61 #undef y
    62 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    63     cnt=read(n),read(m),read(q);
    64     for(register int i=1,x,y;i<=m;++i)read(x),read(y),G1.add(x,y);
    65     for(register int i=1;i<=n;++i)if(!dfn[i])Top=0,tarjan(i);
    66     for(register int i=1,x,y;i<=q;++i)read(x),read(y),Q.add(x,y),++tag[x],++tag[y];
    67     tarjan_lca(1,0);dfs(1);
    68     for(register int i=1;i<=n;++i)printf("%d
    ",tag[i]);
    69     return 0;
    70 }
    View Code

    总结:图中简单路径问题,经过点的统计问题,考虑从点双和圆方树入手。

    顺带一提,点双缩点一般配合圆方树食用,而边双直接缩成一棵树,比如这题如果问必经边的话,一定是割边是必经边(证明同理),只要缩边双后在树上直接差分即可。

  • 相关阅读:
    js实现左侧弹出效果
    [z]重建索引
    Query to find the eligible indexes for rebuilding
    查询oracle比较慢的session和sql
    [z]根据awr报告查看最慢的sql语句
    有关Oracle统计信息的知识点[z]
    [z]表空间对应文件的AUTOEXTEND ON NEXT指定的值对性能的影响
    [z]dbms_stats.lock_table_stats对于没有统计信息的表分区同样有效
    统计sql
    SQL truncate 、delete与drop区别[z]
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11719529.html
Copyright © 2011-2022 走看看