zoukankan      html  css  js  c++  java
  • POJ3417 Network (闇の連鎖) 树上差分 lca

    POJ3417 Network (闇の連鎖)

    树上差分 lca


    POJ3417
    闇の連鎖
    奇奇妙妙的树上差分
    主要边是树的结构
    附加边让树的结构出现环
    手画可以发现
    (xy)为附加边,假如第一次切断了(xy)通过树边相连的路径
    也就是破坏了环
    那么第二次就必定要切断(xy)
    那么就可以通过边差分来解决这个问题
    假如(x)(y)之间有附加边
    在这两个点上记(+1),表示它到它的父亲的边被覆盖
    在lca处(-2)来差分
    dfs求子树和就是当前点到父亲边的覆盖次数
    1.假如覆盖次数为(2)证明没有办法两刀
    2.假如覆盖次数为(1)只能切它子树的附加边
    3.假如覆盖次数为(0)就可以切m个附加边的任意一条
    注意两个OJ数据范围不一样(POJ vector会T,用G++差不多水过去)


    代码如下:

    //#pragma GCC optimize(2)
    #include<cstdio>
    #include<vector>
    #include<map>
    #include<cstring>
    using namespace std;
    const int maxn=100005;
    struct node{
    	int nxt,to;
    	#define nxt(x) e[x].nxt
    	#define to(x) e[x].to
    }e[maxn<<1];
    int id[maxn],n,m,res,head[maxn],tot,fa[maxn],lc[maxn],d[maxn],f[maxn];
    inline void add(int x,int y){
    	to(++tot)=y;nxt(tot)=head[x];head[x]=tot;
    }
    vector<int> as[maxn],as_id[maxn];
    pair<int,int> q[maxn];
    int find(int x){return fa[x]==x ? fa[x] : fa[x]=find(fa[x]);}
    void tarjan(int x){
    	id[x]=1;
    	for(int i=head[x];i;i=nxt(i)){
    		if(id[to(i)]) continue;
    		tarjan(to(i));
    		fa[to(i)]=x;
    	}
    	for(unsigned int i=0;i<as[x].size();i++){
    		if(id[as[x][i]]==2)
    			lc[as_id[x][i]]=find(as[x][i]);
    	}
    	id[x]=2;
    }
    void dfs(int x){
    	id[x]=1;
    	for(int i=head[x];i;i=nxt(i)){
    		if(id[to(i)]) continue;
    		dfs(to(i));
    		f[x]+=f[to(i)];
    	}
    	f[x]+=d[x];
    	if(!f[x]) res+=m;
    	else if(f[x]==1) res+=1;
    }
    int main()
    {
    	//freopen("1.in","r",stdin);
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<n;i++){
    		int x,y;scanf("%d%d",&x,&y);add(x,y);add(y,x);
    		fa[i]=i;
    	}
    	fa[n]=n;
    	for(int i=1;i<=m;i++){
    		int x,y;scanf("%d%d",&x,&y);
    		if(x==y) lc[i]=x;
    		as[x].push_back(y);as_id[x].push_back(i);
    		as[y].push_back(x);as_id[y].push_back(i);
    		q[i].first=x;q[i].second=y;
    	}
    	tarjan(1);
    	for(int i=1;i<=m;i++){
    		d[q[i].first]++;d[q[i].second]++;
    		d[lc[i]]-=2;
    	}
    	memset(id,0,sizeof(id));
    	dfs(1);
    	printf("%d",res-m);//去掉1节点
    	return 0;
    }
    
  • 相关阅读:
    LightOJ 1300 边双联通分量+交错路染色
    HDU 6143 快速幂,组合数
    windows 下fc工具
    HDU 6136 模拟
    HDU 6129 暴力,规律
    UVA Live 7770 模拟
    1096: [ZJOI2007]仓库建设
    1191: [HNOI2006]超级英雄Hero
    3224: Tyvj 1728 普通平衡树
    1208: [HNOI2004]宠物收养所
  • 原文地址:https://www.cnblogs.com/ChrisKKK/p/11608402.html
Copyright © 2011-2022 走看看