今天写了一道数据结构的经典题---树的统计,尝试用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了。