原题链接:https://vjudge.net/problem/UVA-12219
分类:树论
备注:思维
很好的一道题,开始看了lrj的提示后,我先建树给每个结点编号,再独立地又给子树编号,然后再输出,分出了3个DFS,很显然直接TLE了。
后来看了别人的代码,重复子树这一特性可以直接在输出的和建树的时候就用,这样就能减少很多操作,根本不需要给每个结点编号。
还有利用cur一遍遍历直接建树也是一个好的技巧。
因为map,所以最后复杂度为nlogn。
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
char s[maxn];
bool vis[maxn];
int nc,cur;
struct node{
string op;
int lch,rch;
bool operator < (const node &x) const{
return op<x.op||(op==x.op&&lch<x.lch)||(op==x.op&&lch==x.lch&&rch<x.rch);
}
}p[maxn];
map<node,int>id;
int build_tree(){
int index=++nc;
p[index].op="";
p[index].lch=p[index].rch=0;
while(isalpha(s[cur])){
p[index].op+=s[cur];
cur++;
}
if(s[cur]=='('){
cur++;//跳过'('
p[index].lch=build_tree();
cur++;//跳过','
p[index].rch=build_tree();
cur++;//跳过')'
}
if(!id.count(p[index]))id[p[index]]=index;
else --nc;
return id[p[index]];
}
void print(int rt){
if(vis[id[p[rt]]]){
printf("%d",id[p[rt]]); return;
}
printf("%s",p[rt].op.c_str());
vis[id[p[rt]]]=true;
if(!p[rt].lch)return;
printf("(");
print(p[rt].lch);
printf(",");
print(p[rt].rch);
printf(")");
}
int main(void){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int c; scanf("%d",&c);
while(c--){
scanf("%s",s);
id.clear(); nc=cur=0;
memset(vis,false,sizeof(vis));
print(build_tree());
printf("\n");
}
return 0;
}