Codeforces 1182D Complete Mirror [树哈希]
中考考完之后第一个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 [树哈希]的更多相关文章
- Codeforces 1182D Complete Mirror 树的重心乱搞 / 树的直径 / 拓扑排序
题意:给你一颗树,问这颗树是否存在一个根,使得对于任意两点,如果它们到根的距离相同,那么它们的度必须相等. 思路1:树的重心乱搞 根据样例发现,树的重心可能是答案,所以我们可以先判断一下树的重心可不可 ...
- [codeforces 241]C. Mirror Box
[codeforces 241]C. Mirror Box 试题描述 Mirror Box is a name of a popular game in the Iranian National Am ...
- Colored Sticks (字典树哈希+并查集+欧拉路)
Time Limit: 5000MS Memory Limit: 128000K Total Submissions: 27704 Accepted: 7336 Description You ...
- UOJ#373. 【ZJOI2018】线图 搜索,树哈希,动态规划
原文链接www.cnblogs.com/zhouzhendong/p/UOJ373.html 前言 真是一道毒瘤题.UOJ卡常毒瘤++.我卡了1.5h的常数才过QAQ Orzjry 标算居然是指数做法 ...
- LOJ.6066.[2017山东一轮集训Day3]第二题(树哈希 二分)
LOJ 被一件不愉快的小事浪费了一个小时= =. 表示自己(OI方面的)智商没救了=-= 比较显然 二分+树哈希.考虑对树的括号序列进行哈希. 那么每个点的\(k\)子树的括号序列,就是一段区间去掉距 ...
- 【BZOJ5211】[ZJOI2018]线图(树哈希,动态规划)
[BZOJ5211][ZJOI2018]线图(树哈希,动态规划) 题面 BZOJ 洛谷 题解 吉老师的题目是真的神仙啊. 去年去现场这题似乎骗了\(20\)分就滚粗了? 首先\(k=2\)直接算\(k ...
- BZOJ.4337.[BJOI2015]树的同构(树哈希)
BZOJ 洛谷 \(Description\) 给定\(n\)棵无根树.对每棵树,输出与它同构的树的最小编号. \(n及每棵树的点数\leq 50\). \(Solution\) 对于一棵无根树,它的 ...
- bzoj4337: BJOI2015 树的同构 树哈希判同构
题目链接 bzoj4337: BJOI2015 树的同构 题解 树哈希的一种方法 对于每各节点的哈希值为hash[x] = hash[sonk[x]] * p[k]; p为素数表 代码 #includ ...
- 【BZOJ3162】独钓寒江雪(树哈希,动态规划)
[BZOJ3162]独钓寒江雪(树哈希,动态规划) 题面 BZOJ 题解 忽然翻到这道题目,突然发现就是前几天一道考试题目... 题解: 树哈希,既然只考虑这一棵树,那么,如果两个点为根是同构的, 他 ...
随机推荐
- Manthan, Codefest 19 (open for everyone, rated, Div. 1 + Div. 2) (1208F,1208G,1208H)
1208 F 大意: 给定序列$a$, 求$\text{$a_i$|$a_j$&$a_k$}(i<j<k)$的最大值 枚举$i$, 从高位到低位贪心, 那么问题就转化为给定$x$ ...
- elk docker-compose
version: '3.1' services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:6.2.4 c ...
- 详解Spring Cloud中Hystrix 线程隔离导致ThreadLocal数据丢失
在Spring Cloud中我们用Hystrix来实现断路器,Zuul中默认是用信号量(Hystrix默认是线程)来进行隔离的,我们可以通过配置使用线程方式隔离. 在使用线程隔离的时候,有个问题是必须 ...
- iOS - 外包开发常用第三方库(1)
一:第三方插件1:基于响应式编程思想的oc地址:https://github.com/ReactiveCocoa/ReactiveCocoa2:hud提示框地址:https://github.com/ ...
- H5 - 简学
什么是HTML? HTML 是用来描述网页的一种语言. 0.HTML 指的是超文本标记语言 1.HTML 不是一种编程语言,而是一种标记语言 2.标记语言是一套标记标签 3.HTML 使用标记标签来描 ...
- 【转】Java基础——面试题汇总
1.JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境. JRE:Java Runtime Env ...
- 流程控制 while for
循环执行 计算机最擅长的功能之一就是按照规定的条件,重复执行某些操作,这是程序设计中最能发挥计算机特长的程序结构. 1.while语句 while(表达式){ 各种语句.... } 当表达式的值为tr ...
- Oracle死锁处理实例
Oracle死锁常规语句 1.查询Oracle死锁常规语句 SELECT l.session_id sid, s.serial#, l.locked_mode,l.oracle_username, l ...
- redis重命名flushall和flushdb重启失败
redis重命名flushall和flushdb,将使用中的redis重命名redis会启动失败并且log中有报错 # Unknown command 'flushall' reading the a ...
- Python_比较运算符
1.比较运算符