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. MyBatis Generator 自动生成的POJO对象的使用(一)

    MyBatis Generator 会自动生成以下几种类型的对象(除非你使用MyBatis3DynamicSql 的运行环境): Java Model Objects(总是生成) SQL Map Fi ...

  2. 编写Postgres扩展之四:测试

    原文:http://big-elephants.com/2015-11/writing-postgres-extensions-part-iv/ 编译:http://big-elephants.com ...

  3. 错误 4 error C2039: “Sleep”: 不是“boost::this_thread”的成员

    检查是否是在x64下运行的. #include <pcl/io/openni2_grabber.h> #include <pcl/visualization/cloud_viewer ...

  4. 这些方面做好了才能叫运营-App运营日常

    现在APP的开发推广是时代的潮流,同时也是不少企业的难题.现在我们就来谈谈APP运营的一些问题. 1. 基础运营正常维护产品最日常.最普通的工作,如APP应用包在各大应用市场提交上传等,如安卓渠道,包 ...

  5. 【转载】C#中使用OrderBy和ThenBy等方法对List集合进行排序

    在C#的List操作中,针对List对象集合的排序我们可以使用OrderBy.OrderByDescending.ThenBy.ThenByDescending等方法按照特定的对象属性进行排序,其中O ...

  6. jQuery 事件介绍

    什么是事件?页面对不同访问者的响应叫做事件.事件处理程序指的是当 HTML 中发生某些事件时所调用的方法. 常用的时间主要有以下几种: click()事件:click() 方法是当按钮点击事件被触发时 ...

  7. 基于socket.io客户端与服务端的相互通讯

    socket.io是对websocket的封装,用于客户端与服务端的相互通讯.官网:https://socket.io/. 下面是socket.io的用法: 1.由于使用express开的本地服务,先 ...

  8. VIO的一些随笔

    大公司跑在手机的似乎都是滤波MSCKF那种,有优化的但似乎功耗不行.还有就是杂交的前端滤波后面在挂地图,反正国内的似乎就是SVO, VINS, ORBSLAM,MSCKF组合起来. 缺啥补啥,那个太烂 ...

  9. [LeetCode] 671. 二叉树中第二小的节点 ☆(递归 合并)

    描述 给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0.如果一个节点有两个子节点的话,那么这个节点的值不大于它的子节点的值. 给出这样的一个二叉树,你需要输出所有 ...

  10. 18计科学期总成绩明细 && 小黄衫团队预选

    1.个人所有作业+团队作业总得分排名 2.千帆竞发图 3.各团队每次作业得分汇总 根据团队成绩排名,众志陈成队得分最高,预选为小黄衫团队. 对团队成绩有异议的团队,请在成绩预选发布后的两天内私信助教解 ...