本题的大意是判断一棵树是否是一棵轴对称树。
然后多组数据,= =少考虑了一种情况导致只有30。
hack点是重心不一定在对称轴上,如果有两个重心的话,就不是了。。(我明明想到了这种情况,但是想错了。。以为这种情况与横过来是等价的。)
具体做法就是找出重心来后随便hash(最好是用异或乱搞一下)。
当然标算其实不是hash,而是直接用的字符串,因为我们需要的是对字符串的长度排序,而字符串的长度和等于O(n),所以总复杂度依然是O(nlogn)的。
= =但是不知道为什么这道题的n这么小。。让我觉得非常诧异。明明可以开到10^5的啊。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
#include<process.h>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#define Base 233
inline void in(int &x){
char c=getchar();
while(c<'0'||c>'9')c=getchar();
x=0;
for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';
}
inline unsigned Rand(){
return rand()<<16|rand();
}
int color[10005];
unsigned chash[10005],phash[10005];
int next[20005],ptr[10005],succ[20005],etot;
inline void addedge(int u,int v){
next[etot]=ptr[u],ptr[u]=etot,succ[etot++]=v;
}
int size[10005],Size,fa[10005];
void sizedfs(int node){
size[node]=1;
for(int i=ptr[node];i;i=next[i])
if(succ[i]!=fa[node]){
fa[succ[i]]=node;
sizedfs(succ[i]);
size[node]+=size[succ[i]];
}
}
void hdfs(int node,int ftr){
phash[node]=0;
for(int i=ptr[node];i;i=next[i])
if(succ[i]!=ftr){
hdfs(succ[i],node);
phash[node]+=phash[succ[i]]*3;
}
phash[node]=(phash[node]*Base)^chash[color[node]];
}
bool check(int node,int ftr){
int ans=0;
for(int i=ptr[node];i;i=next[i])
if(succ[i]!=ftr)
ans^=phash[succ[i]];
if(!ans)return 1;
for(int i=ptr[node];i;i=next[i])
if(succ[i]!=ftr&&ans==phash[succ[i]])
return check(succ[i],node);
return 0;
}
struct SS{
unsigned sonhash;
bool flag;
bool operator < (const SS & o)const{
return sonhash<o.sonhash;
}
bool operator == (const SS &o)const{
return sonhash==o.sonhash;
}
}son[10005];
inline bool bin(int node){
int i,j;
//找重心。
fa[node]=0;
sizedfs(node);
Size=size[node];
do{
for(i=ptr[node];i;i=next[i])
if(succ[i]!=fa[node])
if(size[succ[i]]>Size>>1){
node=succ[i];
break;
}
else
if((~Size&1)&&size[succ[i]]==Size>>1){
hdfs(node,succ[i]),hdfs(succ[i],node);
if(phash[node]==phash[succ[i]])return 1;
}
}while(i);
//cout<<"-------"<<node<<"-------\n";
//搞出每棵子树的hash
hdfs(node,0);
//处理出每个子树是否可行
int sontot=0;
for(i=ptr[node];i;i=next[i])son[sontot++]=(SS){phash[succ[i]],check(succ[i],node)};
//for(j=0,i=ptr[node];i;i=next[i],++j)cout<<succ[i]<<":"<<phash[succ[i]]<<","<<son[j].flag<<endl;
sort(son,son+sontot);
son[sontot]=(SS){-1};
//判断是否存在合法链,要求个数<3即可。
int tot=0;
for(i=0;i<sontot;i=j){
j=i+1;
while(son[i]==son[j])++j;
if(j-i&1)
if(son[i].flag)++tot;
else break;
}
if(i==sontot&&tot<3)return 1;
else return 0;
}
int main(){
freopen("tree.in","r",stdin);
//freopen("tree.out","w",stdout);
int T,n,i,j;
for(i=26;i--;)chash[i]=Rand();
in(T);
int u,v;
while(T--){
in(n);
for(i=1;i<=n;++i){
color[i]=getchar();
while(color[i]<'A'||color[i]>'Z')color[i]=getchar();
color[i]-='A';
}
memset(ptr,0,sizeof(ptr));
etot=2;
for(i=n;--i;){
in(u),in(v);
addedge(u,v),addedge(v,u);
}
if(bin(1))puts("SYMMETRIC");
else puts("NOT SYMMETRIC");
}
}