LCA裸题,要求的是每个点在答案中的出现次数。
试着写了一下在线的LCA算法(结果代码量比起那个离线的暴增。。。)
自己的代码:
#include<cstdio>
#include<cmath>
using namespace std;
int n;
struct e
{
int t;
e *n;
e(int t,e *n):t(t),n(n){}
}*f[901]={};
namespace memo
{
e *stk[901]={};
int top=-1;
void recycle(int p)
{
while(p--)
if(f[p])
stk[++top]=f[p],f[p]=0;
}
e *alloc(int t,e *n)
{
if(~top)
{
e *rev=stk[top];
stk[top]=stk[top]->n;
if(!stk[top]) --top;
rev->t=t;rev->n=n;
return rev;
}
return new e(t,n);
}
}
namespace rmq
{
int c[1801][12],now;
int dpt[901];
int first[901];
inline int min(int a,int b)
{return dpt[a]<dpt[b]?a:b;}
void dfs(int x)
{
c[++now][0]=x;
first[x]=now;
for(e *i=f[x];i;i=i->n)
{
dpt[i->t]=dpt[x]+1;
dfs(i->t);
c[++now][0]=x;
}
}
void work()
{
int m=log2(now);
for(int i=1;i<=m;i++)
{
int k=1<<i;
for(int j=1;j<=now;j++)
{
if(j+k>now) break;
c[j][i]=min(c[j][i-1],c[j+(k>>1)][i-1]);
}
}
}
inline int ask(int a,int b)
{
if(first[b]<first[a]) a^=b^=a^=b;
int m=log2(first[b]-first[a]+1);
return min(c[first[a]][m],c[first[b]-(1<<m)+1][m]);
}
}
namespace io
{
int num[901];
int ct[901]={};
int tm=0;
int rt[901];
void read1()
{
int x,z,y;
for(int i=1;i<=n;i++)
{
scanf("%d:(%d)",&x,&z);
while(z--)
{
scanf("%d",&y);
f[x]=memo::alloc(y,f[x]);
rt[y]=tm;
}
}
}
void read2()
{
int x=0,y=0,w;
scanf("%d",&w);
for(int i=1;i<=w;i++)
{
scanf(" (%d %d)",&x,&y);
int z=rmq::ask(x,y);
if(ct[z]==tm) num[z]++;
else ct[z]=tm,num[z]=1;
}
}
void write()
{
for(int i=1;i<=n;i++)
if(num[i]&&ct[i]==tm)
printf("%d:%d\n",i,num[i]);
}
}
namespace ctrl
{
int root()
{
for(int i=1;i<=n;i++)
{
if(io::rt[i]==io::tm)
continue;
return i;
}
}
inline void case_beg()
{
rmq::now=0;
io::tm++;
}
inline void tree_build()
{
int r=root();
rmq::dpt[r]=0;
rmq::dfs(r);
}
inline void main_work()
{
io::read1();
tree_build();
rmq::work();
io::read2();
io::write();
}
inline void case_end()
{
memo::recycle(n);
}
}
int main()
{
while(scanf("%d",&n)==1)
{
ctrl::case_beg();
ctrl::main_work();
ctrl::case_end();
}
return 0;
}