【JSOI2016】独特的树叶
来源:互联网 发布:linux mysqldump 导入 编辑:程序博客网 时间:2024/06/08 15:04
题目大意
有一棵树a,树b是在a的基础上多加一个叶子,且打乱了编号顺序,现在要求b上多出的那个节点是哪个(可能有多个)
暴力
枚举一个节点作为根节点,然后用各种奇怪的依据(例如儿子个数,节点度数,最大子树大小等)来匹配,逐个逐个下去找,大概时间复杂度O(有点玄学)
正解
树的hash
因为是匹配,所以我们可以想到hash,那么对于树的hash我们可以怎样做呢?
很直观的可以用最小表示法,例如求一棵子树的hash,设树根为x,其儿子为a[1..n],以i节点为根的子树的hash值为v[i],那么将其儿子的hash值从小到大排序,弄个素数hash一下,注意最好加上一个依据,不然可能挂掉,时间复杂度是O(n log n)
思路
对于a的每个节点,求出其子树hash值,然后求出作为树根的hash值和其向父亲方向的树的hash值,将每个点作为树根的hash值扔进一个set里,枚举b的一个叶子,用类似的方法求出删掉它之后的树的hash值
code
#include<iostream>#include<algorithm>#include<cstdio>#include<cmath>#include<cstring>#include<set>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;typedef long long LL;const int N = 100010;const int mo = 1e+9+9;const int pri = 12589;LL tim[N],q[N];int k;struct node{ int x; LL v;}u[N];bool cmp(node x,node y){ return x.v<y.v;}struct tree{ struct edge{ int x,next; }e[N*2]; int tot,n; int h[N],r[N],fa[N],s[N]; LL v[N],rt[N],f[N]; LL suf[N],pre[N]; void inse(int x,int y){ e[++tot].x=y; e[tot].next=h[x]; h[x]=tot; } void init(){ tot=0; fo(i,1,n)h[i]=r[i]=v[i]=f[i]=fa[i]=rt[i]=0; fo(i,1,n-1){ int x,y; scanf("%d%d",&x,&y); inse(x,y); inse(y,x); r[x]++; r[y]++; } } void dfs1(int x){ s[x]=1; for(int p=h[x];p;p=e[p].next) if (e[p].x!=fa[x]){ fa[e[p].x]=x; dfs1(e[p].x); s[x]+=s[e[p].x]; } k=0; for(int p=h[x];p;p=e[p].next) if (fa[e[p].x]==x)q[++k]=v[e[p].x]; sort(q+1,q+1+k); v[x]=0; fo(i,1,k)v[x]=(v[x]*pri%mo+q[i])%mo; v[x]=(v[x]*pri%mo+s[x])%mo; } void dfs2(int x){ k=0; if (x>1)u[++k].v=f[x],u[k].x=fa[x]; for(int p=h[x];p;p=e[p].next) if (fa[e[p].x]==x){ u[++k].x=e[p].x; u[k].v=v[e[p].x]; } std::sort(u+1,u+1+k,cmp); fo(i,1,k)pre[i]=(pre[i-1]*pri%mo+u[i].v)%mo; suf[k+1]=0; fd(i,k,1)suf[i]=(suf[i+1]+u[i].v*tim[k-i]%mo)%mo; fo(i,1,k) if (u[i].x!=fa[x]){ f[u[i].x]=(pre[i-1]*tim[k-i]%mo+suf[i+1])%mo; f[u[i].x]=(f[u[i].x]*pri%mo+n-s[u[i].x])%mo; } for(int p=h[x];p;p=e[p].next) if (fa[e[p].x]==x)dfs2(e[p].x); } void calc(){ dfs1(1); dfs2(1); fo(i,1,n){ k=0; for(int p=h[i];p;p=e[p].next) if (fa[e[p].x]==i)q[++k]=v[e[p].x]; if (fa[i])q[++k]=f[i]; sort(q+1,q+1+k); rt[i]=0; fo(j,1,k)rt[i]=(rt[i]*pri%mo+q[j])%mo; rt[i]=(rt[i]*pri%mo+n)%mo; } }}a,b;set<LL> s;int m;int main(){ freopen("leaf.in","r",stdin); freopen("leaf.out","w",stdout); tim[0]=1; s.clear(); scanf("%d",&m); fo(i,1,m+2)tim[i]=tim[i-1]*pri%mo; a.n=m; a.init(); b.n=m+1; b.init(); a.calc(); b.calc(); fo(i,1,m)s.insert(a.rt[i]); fo(i,1,m+1) if (b.r[i]==1&&((i!=1&&s.find(b.f[i])!=s.end())||(i==1&&s.find(b.v[b.e[b.h[i]].x])!=s.end()))){ printf("%d\n",i); break; } fclose(stdin); fclose(stdout); return 0;}
一开始用的模数太小挂掉了啊!!!
0 0
- 【JSOI2016】独特的树叶
- JZOJ4513. 【JSOI2016】独特的树叶
- JSOI2016 独特的树叶 树的Hash判同构
- bzoj4754独特的树叶(树hash)
- [Jsoi2016]扭动的回文串
- 扫树叶的小和尚
- 扫树叶的小和尚
- 下落的树叶
- ps树叶的雕刻
- 例题:下落的树叶
- [bzoj4755][JSOI2016]扭动的回文串
- BZOJ4755 [Jsoi2016]扭动的回文串
- 自己的独特内容
- 独特的ARM
- 独特的价值。
- 独特的经历
- android独特的天气预报
- 做独特的自己
- iOS触摸事件/响应者链条
- 欢迎使用CSDN-markdown编辑器
- 移动弱网测试
- Spring AOP切面实现:解析
- laravel_安装
- 【JSOI2016】独特的树叶
- array.push()方法的用法
- C++实现RTMP协议发送H.264编码及AAC编码的音视频,摄像头直播
- 谱聚类算法(Spectral Clustering)优化与扩展
- C# 读写TXT文件遇到乱码问题
- 当WPS文件保存并关闭后恢复的方法。
- 纹理分割(四)Snakes相关知识备份
- Android热补丁技术方案整理
- Android TabLayout(选项卡布局)简单用法实例分析