给定一棵树,第一次出现的结点直接输出,并编号。如果有重复的子树,就输出该子树的根的编号。
//非常神奇的递归
#include <iostream>
#include <cstdio>
#include <map>
#include <string>
using namespace std;
const int maxn = 5e4 + 5;
char line[maxn << 3],*p;
int cn = 0;
int cnt = 0;
int done[maxn];//该结点是否已输出,即第一次输出串,之后输出数字
struct Node{
string s;
int rt,lc,rc;
bool operator < (const Node &a) const{
if(rt != a.rt) return rt < a.rt;
if(lc != a.lc) return lc < a.lc;
return rc < a.rc;
}
}node[maxn];
map<Node,int> mp;
int parse()
{
int id = cnt ++;
Node &u = node[id];
u.lc = u.rc = -1;
u.s = "";
u.rt = 0;
while (isalpha(*p)) {
u.rt = u.rt * 27 + *p - 'a' + 1;
u.s += *p;
p ++;
}
if(*p == '('){//(L,R)
p ++;u.lc = parse();p ++;u.rc = parse();p ++;
}
if(mp.find(u) != mp.end()){
id --,cnt --;
return mp[u];
}
return mp[u] = id;
}
void print(int v)
{
if(done[v] == cn){
printf("%d",v + 1);
}
else{
done[v] = cn;//避免memset
printf("%s",node[v].s.c_str());
if(node[v].lc != -1){
putchar('(');
print(node[v].lc);
putchar(',');
print(node[v].rc);
putchar(')');
}
}
}
int main()
{
int T;
scanf("%d%*c",&T);
for(cn = 1;cn <= T;cn ++) {
scanf("%s",line);
mp.clear();
cnt = 0;
p = line;
print(parse());
putchar('\n');
}
return 0;
}