数据结构数据生成器--生成树 bzoj1036

今天写了一道数据结构的经典题---树的统计,尝试用LCT写,结果不造怎的可以过样例,但交上去就WA,苦于肉眼找不出错,于是翻出了以前写的树立剖分的版本,想来搞搞对拍。

然而~~~~~尼玛树怎么构造啊- -


然后沉思- -,网上搜索,找不到- - -- - - - -- - - - 


然后想起来了purfer编码,咦,purfer编码不就是搞树的么。

还记得purfer编码是可以把一棵树转成purfer编码的,而且也可以由purfer编码转成树!


先把purfer编码中每个数出现一次就把度数+1(初始化每个点度数为1)


然后顺序枚举purfer编码的每一个i,在度数表里面找度数为1的编号最小的那一个,把当前i和度数表里面标号最小的那个度数同时-1,然后这两个点之间连边.

(有没有可能自己和自己连边呢?我也考虑过,结果发现自己太蠢了:   自己和自己连边说明purfer编码里面有一个自己,它的度至少为2,这样在度数表里面不可能选到它,就矛盾了,所以这个想法是不成立的)


然后最后会剩下两个度数为1的点,他们之间再连一条边就好了。

这样,一棵树就形成了、


为了操作方便,我使用了结构体,随时排序,找编号和找度数为1且编号最小的点:

(可能有点慢)核心部分在主函数里面

makedata   bzoj1036

#include<cstdio>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<algorithm>
using namespace std;
int a[30000+20];
struct nod
{
	int id,d;
}d[30000+20];
bool cmpid(nod x,nod y)//按编号排序
{
	return x.id<y.id;
}
bool cmp(nod x,nod y)//按度数排序
{
	if(x.d!=y.d)return x.d<y.d;
	else return x.id<y.id;
}
int main()
{
	freopen("1.in","w",stdout);
	srand(time(NULL));
	int n=rand()%10+1;
	cout<<n<<endl;
	for(int i=1;i<=n;i++)
	{
		d[i].d=1;
		d[i].id=i;
	}
	for(int i=1;i<=n-2;i++)a[i]=rand()%n+1;//生成purfer编码
	for(int i=1;i<=n-2;i++)d[a[i]].d++;//累加度数
	for(int i=1;i<=n-2;i++)
	{
		sort(d+1,d+n+1,cmp);
		int j;
		for(j=1;j<=n;j++)if(d[j].d)break;
		printf("%d %d\n",d[j].id,a[i]);
		d[j].d--;
		sort(d+1,d+n+1,cmpid);
		d[a[i]].d--;
	}                                //模拟上述过程,找度数为1且编号最小的和purfer编码中当前位
	sort(d+1,d+n+1,cmp);
	printf("%d %d\n",d[n-1].id,d[n].id);//最后两个点之间连边
	for(int i=1;i<=n;i++)
	{
		printf("%d ",(rand()%20)-10);
	}
	int m=rand()%20+1;
	cout<<endl;
	cout<<m<<endl;
	for(int i=1;i<=m;i++)
	{
		int s=rand()%3+1;
		if(s==1)printf("QMAX ");
		if(s==2)printf("QSUM ");
		if(s==3)printf("CHANGE ");
		int a=rand()%n+1;
		int b=rand()%a+1;
		while(a==b)
		{
			a=rand()%n+1;
		    b=rand()%a+1;
		}
		cout<<a<<" "<<b<<endl;
	}
	return 0;
}

有了这个数据生成器,就可以对拍了,然后就找出错,发现自己萌的可爱- -

错误点:max的初始化为0,结果权值可能为负,一求max就变成了0,就WA了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值