zoukankan      html  css  js  c++  java
  • 【题解】一本通1553:【例 2】暗的连锁

    [题目](http://ybt.ssoier.cn:8088/problem_show.php?pid=1553)

    前置知识:倍增求LCA(当然不倍增也行)

    1553:【例 2】暗的连锁

    时间限制: 1000 ms 内存限制: 524288 KB
    提交数: 456 通过数: 201

    【题目描述】

    原题来自:POJ 3417

    Dark 是一张无向图,图中有 NN 个节点和两类边,一类边被称为主要边,而另一类被称为附加边。Dark 有 N–1N–1 条主要边,并且 Dark 的任意两个节点之间都存在一条只由主要边构成的路径。另外,Dark 还有 MM 条附加边。

    你的任务是把 Dark 斩为不连通的两部分。一开始 Dark 的附加边都处于无敌状态,你只能选择一条主要边切断。一旦你切断了一条主要边,Dark 就会进入防御模式,主要边会变为无敌的而附加边可以被切断。但是你的能力只能再切断 Dark 的一条附加边。

    现在你想要知道,一共有多少种方案可以击败 Dark。注意,就算你第一步切断主要边之后就已经把 Dark 斩为两截,你也需要切断一条附加边才算击败了 Dark。

    【输入】

    第一行包含两个整数 NN 和 MM;

    之后 N–1N–1行,每行包括两个整数 AA 和 BB,表示 AA 和 BB 之间有一条主要边;

    之后 MM 行以同样的格式给出附加边。

    【输出】

    输出一个整数表示答案。

    【输入样例】

    4 1
    1 2
    2 3
    1 4
    3 4

    【输出样例】

    3

    【提示】

    数据范围与提示:

    对于 20% 的数据,1≤N,M≤1001≤N,M≤100;

    对于 100% 的数据,1≤N≤105,1≤M≤2×1051≤N≤105,1≤M≤2×105 。数据保证答案不超过 231−1231−1。
    (看数据会发现:两点之间直接相连的附加边可能有很多条;自己与自己也能连接一条附加边)

    题解

    附加边:

    添加一条附加边,不仅会造成这条边直接相连的两个点之间的主要边受阻,还会造成其他的一些边受阻
    这里的受阻,是指砍除两点之间的主要边之后,必须再砍除这条附加边,才能将树分成两段

    受阻范围:

    就是从附加边连接的两点,到它们的LCA之间的所有边。也就是这两点之间的最短路径

    贡献解的条件:

    若砍除一条主要边之后,再砍掉它受阻的附加边,能将原树分成两半,那么这条边受阻的附加边必然不大于2
    所以我们要记录每一条主要边受几条附加边的阻碍

    怎么记录?:

    只要这条边在附加边阻碍范围的最短路径上,也就是在lca为根的树上,就会受阻;但一旦这条边出了lca子树,便不受阻。可以理解为在lca子树里,lca和附加边造成的阻碍相互抵消了。
    因此我们可以利用差分的思想

    变量和函数

    k[]&&cha(x,y):一条附加边连接x和y,它们的LCA用函数find_LCA(x,y)找到,那么将k[x]和k[y]都加一,将k[find_LCA(x,y)]减二,就实现了差分
    quan[]&&get_quan():对于连接点u和它的父亲fa的边x,计算出以u为根的子树的所有节点的k[]之和,就是边x所受的阻碍次数(这个不难想诶,,,)
    get_LCA&&f[][]&&dep[]:求LCA嘛,不多说

    方案数

    唉,交了三遍才发现题目让求的是方案数,不是主要边的数量。。。
    如果这条主要边受阻0次,那砍完这条主要边后,从所有的附加边中随便砍一条,答案加m;
    如果它受阻1次,那砍完它后必须再砍断阻碍它的附加边,答案加1
    所以:code:

    #include <cmath>
    #include <cstdio>
    #include <string>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define F(i,a,b) for(int i=a;i<=b;i++)
    #define UF(i,a,b) for(int i=a;i>=b;i--)
    #define N 100010
    #define M 200010
    using namespace std;
    int n, m, next[N], fir[N], to[N], len, k[N], quan[N], x, y, f[N][25], ans, dep[N];
    void ins(int x, int y)
    {
    	len++;
    	next[len]=fir[x];
    	to[len]=y;
    	fir[x]=len;
    	/*len++;
    	next[len]=fir[y];
    	to[len]=x;
    	fir[y]=len;*/
    }
    void deal_first(int u, int fa)
    {
    	dep[u]=dep[fa]+1;
    	F(i,0,19){
    		f[u][i+1]=f[f[u][i]][i];
    	}
    	for(int e=fir[u];e;e=next[e]){
    		int v=to[e];
    		f[v][0]=u;
    //		cout << v << " ";
    		deal_first(v,u);
    	}//cout << endl;
    }
    int find_LCA(int x, int y)
    {
    	if(x==y){
    		return x; 
    	}
    	if(dep[x]<dep[y])	swap(x,y);
    	UF(i,20,0){
    		if(dep[f[x][i]]>=dep[y])	x=f[x][i];
    		if(x==y){
    			return x; 
    		}
    	}
    	UF(i,20,0){
    		if(f[x][i]!=f[y][i]){
    			x=f[x][i];
    			y=f[y][i];
    		}
    	}
    	return f[x][0]; 
    }
    void cha(int x, int y)
    {
    	k[x]+=1;
    	k[y]+=1;
    	k[find_LCA(x,y)]-=2;
    	return;
    }
    void get_quan(int x, int u, int fa)
    {
    //	cout << "*";
    	if(quan[x] != N)	return;
    	quan[x]=0;
    	for(int e=fir[u];e;e=next[e]){
    		int v=to[e];
    		get_quan(e,v,u);
    		quan[x]+=quan[e];
    	}
    	quan[x]+=k[u];
    	if(quan[x]<=1 && x!=0){
    		if(quan[x]==0)	ans+=m;
    		if(quan[x]==1)	ans+=1;
    	}
    	return;
    }
    
    void check()
    {
    	printf("len=%d
    ",len);
    	F(i,1,n){
    		for (int e=fir[i];e;e=next[e])
    		{
    			cout << to[e] << " ";
    		}cout << endl;
    	}
    }void check02()
    {
    	F(i,1,n)	cout<<dep[i]<<" ";
    	cout << endl;
    	F(i,1,n){
    		F(j,0,2)
    			cout << f[i][j] << " ";
    		cout << endl;
    	}
    }
    void check03()
    {
    	F(i,1,n)	cout << k[i] << " ";
    	cout << endl;
    }
    void check04()
    {
    	F(i,0,len)	cout << quan[i] << " ";
    	cout << endl;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	F(i,1,n-1){
    		scanf("%d%d",&x,&y);
    		ins(x,y);
    	}
    	deal_first(1,0);
    	F(i,1,m){
    		scanf("%d%d",&x,&y);
    		cha(x,y);
    	}
    	F(i,0,len)	quan[i]=N;
    //	check();
    //	check02();
    //	check03();
    	get_quan(0,1,0);
    //	check04();
    	printf("%d",ans);
    	return 0;
    }
    /*
    7 3
    1 2
    1 7 
    2 3
    2 4
    2 5
    3 6
    3 4
    4 5
    4 6
    */
    
  • 相关阅读:
    解决VS打开文件出现No EditorOptionDefinition export found for the given option name问题
    git SourceTree 客户端 安装/使用教程
    C#调用WebService实例和开发
    Web Service 和WCF的比较
    Web Service 消息格式
    C#如何使用REST接口读写数据
    解决EasyNVR现场无固定公网IP的问题,万千企业期待的EasyNVS管理平台是什么?
    借助EasyNTS云组网,无需拉专线,也能解决设备现场无公网固定IP的问题
    EasyPlayer-RTSP-Android安卓播放器播放RTSP延迟优化策略,极低延时!
    EasyNVR现场部署搭配EasyNVS云端集中控制应用于幼儿园直播场景的最佳方案!
  • 原文地址:https://www.cnblogs.com/ZhengkunJia/p/12275722.html
Copyright © 2011-2022 走看看