Codeforces

中考考完之后第一个AC,纪念一下qwq

思路

简单理解一下题之后就可以发现其实就是要求一个点,使得把它提为根之后整棵树显得非常对称。

很容易想到树哈希来判结构是否相同,而且由于只有完全对称的时候才有用,所以比普通哈希还简单一些……

吗?

你需要求出子树哈希值、祖先哈希值,还要记下来这个点下面是否都相等,还是会有一个捣乱的,还是整个都是乱的。

然后还要特判一个儿子、两个儿子、没有儿子……

于是开开心心地150行了,删掉缺省源之后大概100行。

emmm说的好像不是很清晰,那再说一遍吧。

提为根之后一定是先一段度数为1的点,然后开始分叉,其中每一层的分叉数相同。

如果一个点的儿子的子树全都一样且合法,那就非常好。(非常好是什么鬼啊)

如果有一个特立独行的儿子,那么根肯定在那里面,要把这个儿子给记下来。

如果有两个以上的不一样的或是不合法的,那么就算是废了。

注意还要换根DP一下搞出一个点上方的哈希值,因为提为根之后上面的就变成了一棵子树了。

注意还要各种特判……

代码

哈希值-1表示不合法,\(dn,up\)表示整棵子树/上方,\(W\)表示比较普通的儿子的哈希值,\(son1\)表示记录那个特立独行的儿子。

感谢@litble神仙指出错误,已经改正

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pli pair<ll,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 101010
#define mod 998244353ll
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char __sr[1<<21],__z[20];int __C=-1,__zz=0;
inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
inline void print(register int x)
{
if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
while(__z[++__zz]=x%10+48,x/=10);
while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
}
void file()
{
#ifdef NTFOrz
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std; int n;
struct hh{int t,nxt;}edge[sz<<1];
int head[sz],ecnt;
void make_edge(int f,int t)
{
edge[++ecnt]=(hh){t,head[f]};
head[f]=ecnt;
edge[++ecnt]=(hh){f,head[t]};
head[t]=ecnt;
} ll dn[sz],up[sz];
int son1[sz];
ll W[sz];
int son[sz];
#define v edge[i].t
void dfs1(int x,int fa)
{
int cnt=0;
vector<pli>V;int cc=0,s=0;
go(x) if (v!=fa)
{
dfs1(v,x);++cnt;
if (dn[v]!=-1) V.push_back(MP(dn[v],v));
else ++cc,s=v;
}
if (cnt==0) return (void)(dn[x]=0,W[x]=son1[x]=-1);
sort(V.begin(),V.end());
son[x]=cnt;
if (cc) dn[x]=-1,son1[x]=s;
if (cc>1) return (void)(son1[x]=W[x]=-1);
if (cnt==1)
{
if (cc) W[x]=-1;
else dn[x]=(V[0].fir*sz%mod+1)%mod,W[x]=V[0].fir,son1[x]=-1;
return;
}
if (cc)
{
if (V[0].fir==V[cnt-2].fir) W[x]=V[0].fir;
else W[x]=-1;
return;
}
if (V[0].fir==V[cnt-1].fir) dn[x]=((W[x]=V[0].fir)*sz%mod+cnt)%mod,son1[x]=-1;
else if (V[0].fir==V[cnt-2].fir) dn[x]=-1,W[x]=V[0].fir,son1[x]=V[cnt-1].sec;
else if (V[1].fir==V[cnt-1].fir) dn[x]=-1,W[x]=V[1].fir,son1[x]=V[0].sec;
else dn[x]=W[x]=son1[x]=-1;
}
void dfs2(int x,int fa)
{
go(x) if (v!=fa)
{
if (son[x]==1)
{
if (x==1) up[v]=0;
else if (up[x]==-1) up[v]=-1;
else up[v]=(up[x]*sz%mod+1)%mod;
}
else if (dn[x]!=-1||son1[x]==v)
{
if (x==1) up[v]=(W[x]*sz%mod+son[x]-1)%mod;
else if (up[x]==W[x]&&up[x]!=-1) up[v]=(W[x]*sz%mod+son[x])%mod;
else up[v]=-1;
}
else if (son[x]==2&&son1[x]!=-1)
{
ll w=dn[son1[x]];
if (w==-1) up[v]=-1;
else if (x==1) up[v]=(w*sz%mod+1)%mod;
else if (w==up[x]) up[v]=(w*sz%mod+2)%mod;
else up[v]=-1;
}
else up[v]=-1;
dfs2(v,x);
}
} int main()
{
file();
read(n);
if (n<=3) return puts("1"),0;
int x,y;
rep(i,1,n-1) read(x,y),make_edge(x,y);
dfs1(1,0);
rep(i,1,n) up[i]=-1;
dfs2(1,0);
if (dn[1]!=-1) return puts("1"),0;
rep(i,2,n) if (up[i]==W[i]&&dn[i]!=-1&&son[i]) return printf("%d",i),0;
rep(i,2,n) if (!son[i]&&up[i]!=-1) return printf("%d",i),0;
puts("-1");
return 0;
}

Codeforces 1182D Complete Mirror [树哈希]的更多相关文章

  1. Codeforces 1182D Complete Mirror 树的重心乱搞 / 树的直径 / 拓扑排序

    题意:给你一颗树,问这颗树是否存在一个根,使得对于任意两点,如果它们到根的距离相同,那么它们的度必须相等. 思路1:树的重心乱搞 根据样例发现,树的重心可能是答案,所以我们可以先判断一下树的重心可不可 ...

  2. [codeforces 241]C. Mirror Box

    [codeforces 241]C. Mirror Box 试题描述 Mirror Box is a name of a popular game in the Iranian National Am ...

  3. Colored Sticks (字典树哈希+并查集+欧拉路)

    Time Limit: 5000MS   Memory Limit: 128000K Total Submissions: 27704   Accepted: 7336 Description You ...

  4. UOJ#373. 【ZJOI2018】线图 搜索,树哈希,动态规划

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ373.html 前言 真是一道毒瘤题.UOJ卡常毒瘤++.我卡了1.5h的常数才过QAQ Orzjry 标算居然是指数做法 ...

  5. LOJ.6066.[2017山东一轮集训Day3]第二题(树哈希 二分)

    LOJ 被一件不愉快的小事浪费了一个小时= =. 表示自己(OI方面的)智商没救了=-= 比较显然 二分+树哈希.考虑对树的括号序列进行哈希. 那么每个点的\(k\)子树的括号序列,就是一段区间去掉距 ...

  6. 【BZOJ5211】[ZJOI2018]线图(树哈希,动态规划)

    [BZOJ5211][ZJOI2018]线图(树哈希,动态规划) 题面 BZOJ 洛谷 题解 吉老师的题目是真的神仙啊. 去年去现场这题似乎骗了\(20\)分就滚粗了? 首先\(k=2\)直接算\(k ...

  7. BZOJ.4337.[BJOI2015]树的同构(树哈希)

    BZOJ 洛谷 \(Description\) 给定\(n\)棵无根树.对每棵树,输出与它同构的树的最小编号. \(n及每棵树的点数\leq 50\). \(Solution\) 对于一棵无根树,它的 ...

  8. bzoj4337: BJOI2015 树的同构 树哈希判同构

    题目链接 bzoj4337: BJOI2015 树的同构 题解 树哈希的一种方法 对于每各节点的哈希值为hash[x] = hash[sonk[x]] * p[k]; p为素数表 代码 #includ ...

  9. 【BZOJ3162】独钓寒江雪(树哈希,动态规划)

    [BZOJ3162]独钓寒江雪(树哈希,动态规划) 题面 BZOJ 题解 忽然翻到这道题目,突然发现就是前几天一道考试题目... 题解: 树哈希,既然只考虑这一棵树,那么,如果两个点为根是同构的, 他 ...

随机推荐

  1. idea 中 下载源码:Sources not download for:

    使用idea 下载源码出现:Sources not found for: 解决方案:在对应的pom.xml 文件中打开 terminal,执行 mvn命令: mvn dependency:source ...

  2. ifconfig介绍

    [root@controller01 ~]# ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNK ...

  3. 2.MVC基础-Model概述(思维导图)

    已思维导图形式,便于记忆和补充

  4. python——操作系统的发展史

    一.手工操作 —— 穿孔卡片 1946年第一台计算机诞生--20世纪50年代中期,计算机工作还在采用手工操作方式.此时还没有操作系统的概念.    程序员将对应于程序和数据的已穿孔的纸带(或卡片)装入 ...

  5. 如何去把内容分享到whatsapp上?

    使用场景,公司利用whatsapp来推广商品,需要把商品和一些基本信息分享到WhatsApp上; 一:在html的head标签里面通过meta标签加上一些分享的基本网站信息,具体代码如下 <me ...

  6. Lwip与底层的接口

    Lwip有三套api,分别是: raw api:使用方法为使用回调函数,即先注册一个函数,当接受到数据之后调用这个函数.缺点是对于数据连续处理不好. Lwip api:把接收与处理放在一个线程里面.因 ...

  7. Installation Manager1.8安装

    1.下载地址: https://www-01.ibm.com/marketing/iwm/iwm/web/download.do?S_PKG=500005026&source=swerpws- ...

  8. Oracle查看占用表空间最大的表(排序)

    场景:在做数据库巡检时,检查大表是必不可少的操作,可以查看各表占用表空间的大小 代码: as sizes,q.num_rows,t.segment_type from dba_segments t l ...

  9. Computer Vision_33_SIFT:A novel coarse-to-fine scheme for automatic image registration based on SIFT and mutual information——2014

    此部分是计算机视觉部分,主要侧重在底层特征提取,视频分析,跟踪,目标检测和识别方面等方面.对于自己不太熟悉的领域比如摄像机标定和立体视觉,仅仅列出上google上引用次数比较多的文献.有一些刚刚出版的 ...

  10. Android笔记(二十六) Android中的广播——BroadcastReceiver

    为了方便进行系统级别的消息通知,Android有一套类似广播的消息机制,每个应用程序都可以对自己感兴趣的广播进行注册,这样该程序就只会接收自己所关心的广播内容,这些广播可能是来自于系统,也可能是来自于 ...