bzoj 1977 (浅谈如何hack掉hzwer学长)(严格次小生成树)(LCA+kruskal)

传送门

题解:以下内容出自题解没错但是代码有错却过了bzoj评测的hwzer学长先求出最小生成树,要严格次小。枚举每一条非树边找俩顶点树链上的最大边(如果最大边相同与非树边边权相同则找次大边)然后更新最小增量。最大边和次大边可以通过树上倍增求出。

下证hzwer学长和其他一些同学的错误,以hzwer的代码为例:

void cal(int x,int f,int v)
{
    int mx1=0,mx2=0;
    int t=deep[x]-deep[f];
    for(int i=0;i<=16;i++)
    {
        if(t&(1<mx1)
           {
           	   mx2=mx1;
           	   mx1=d1[x][i];
           }
           mx2=max(mx2,d2[x][i]);
           x=fa[x][i];
        }
    }
    if(mx1!=v)mn=min(mn,v-mx1);
    else mn=min(mn,v-mx2);
}
先用文字说一遍:当之前已算过的最大值大于当期的最大值时,当前最大值可以用来更新次大值,他并没有这么做。
再用代码解释一遍:当mx1>d1[x][i]时,d1[x][i]可以用来更新mx2,而他并没有这么做。

再说说如何hack掉这类代码:

方案1.出一组如下数据(就是将样例的点的编号进行一些交换):


5 6
1 2 2
1 5 4
2 3 1
3 4 3
1 4 3
5 4 6

答案是11,典型错误是12。

方案2.直接将hzwer的dfs(1)改为dfs(3),次小生成树的大小与根的选取无关,但是它跑出了错误的答案(12)。


P.S.WA了一大晚上因为kruskal没sort。。。但是在调试过程中有了这么多新发现也算值了。

下面是严格的正解

#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define pii pair
#define mp(x,y) make_pair(x,y)
const int MAXN=1e5+4,MAXM=3e5+4;
int n,m,mm=0,root;
int head[MAXN],etot=0;
struct EDGE {
    int v,nxt,w;
}e[MAXN<<1];
int dep[MAXN],mx[18][MAXN],ms[18][MAXN],f[18][MAXN];
ll mst=0;
int delta=0x3f3f3f3f;
inline int read() {
	int x=0;char c=getchar();
	while (c<'0'||c>'9') c=getchar();
	while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	return x;
}
inline void adde(int u,int v,int w) {
	e[etot].nxt=head[u],e[etot].v=v,e[etot].w=w,head[u]=etot++;
	e[etot].nxt=head[v],e[etot].v=u,e[etot].w=w,head[v]=etot++;
}
/*---------------kruskal---------------*/
struct M_EDGE {
	int u,v,w;
	friend bool operator <(const M_EDGE &a,const M_EDGE &b) {
		return a.w1;++i) {
		int u=find(d[i].u),v=find(d[i].v);
		if (u^v) {
			mst+=d[i].w;
			fa[u]=v,--blo;
			adde(d[i].u,d[i].v,d[i].w);
			sel[i]=true;
			root=d[i].u;
		}
	}
}
/*---------------LCA---------------*/
void dfs(int p,int father) {
	f[0][p]=father,dep[p]=dep[father]+1;
	for (int i=head[p];~i;i=e[i].nxt) {
		int v=e[i].v;
		if (v^father) {
			mx[0][v]=e[i].w;
			dfs(v,p);
		}
	}
}
inline void da() {
	for (int j=1;(1<


你可能感兴趣的:(图论)