嗯,今年GD出题人和SC出题人都偶然的出了同一个算法的题啊。
精简的题目描述
有一棵树,每个点有一个小写字母,树上有些路径是回文串,求这样的树有多少棵。
将【SCOI2016萌萌哒】的模型放到树上。
给ST表每个块两个标号,分别表示正和反。
处理一个回文串的状态,首先将一条路径的两端先处理。
然后处理剩下的一条只有祖先的路,一开始我是用直观的方法,log^2合并的,后来发现很慢,就改成先将该路径分成log个块,存下每个块的开头和2的幂数,然后从尾开始合并。
然后,就跟【SCOI2016萌萌哒】差不多了。
由于我傻逼地不知道c++里log()很慢,导致超时了n次……
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N = 100010;
const int mo = 1e+9+7;
typedef long long LL;
int h[N],n,tot,m;
struct edge{
int x,next;
}e[N];
int k;
int fa[N*40];
int dep[N],u,f[N][20];
int q[N*40],p[N*40];
bool pd[N*40];
int que[N];
int v[20],op,ss[20];
int rank[N*40];
double lim;
int to[N];
void inse(int x,int y){
e[++tot].x=y;
e[tot].next=h[x];
h[x]=tot;
}
void bfs(){
int head=0,tail=1;
que[1]=dep[1]=1;
while(head<tail){
int x=que[++head];
fo(i,1,lim)f[x][i]=f[f[x][i-1]][i-1];
for(int p=h[x];p;p=e[p].next)
if (!dep[e[p].x]){
dep[e[p].x]=dep[x]+1;
f[e[p].x][0]=x;
que[++tail]=e[p].x;
}
}
}
void prepare(){
fo(i,0,(lim+1)*n*2+1){
fa[i]=i;
rank[i]=1;
}
}
int lca(int x,int y){
if (dep[x]<dep[y])swap(x,y);
fd(i,lim,0)
if (dep[f[x][i]]>=dep[y])x=f[x][i];
if (x==y)return x;
fd(i,lim,0)
if (f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
int getfather(int x){
if (fa[x]==x)return x;
return fa[x]=getfather(fa[x]);
}
int pt(int x,int y,int z){
return (y*n+x)*2+z;
}
void tog(int x,int y){
x=getfather(x),y=getfather(y);
if (x==y)return;
if (rank[x]>rank[y])fa[y]=x;
else{
fa[x]=y;
if (rank[x]==rank[y])rank[y]++;
}
}
int main(){
freopen("paltree.in","r",stdin);
freopen("paltree.out","w",stdout);
scanf("%d",&n);
fo(i,1,n-1){
int x,y;
scanf("%d%d",&x,&y);
inse(x,y);
inse(y,x);
}
lim=log(n)/log(2);
bfs();
prepare();
scanf("%d",&m);
fo(u,1,m){
int x,y;
scanf("%d%d",&x,&y);
int tf=lca(x,y);
fd(i,lim,0)
if(dep[f[x][i]]>=dep[tf]&&dep[f[y][i]]>=dep[tf]){
tog(pt(x,i,0),pt(y,i,0));
x=f[x][i];
y=f[y][i];
}
if (dep[x]<dep[y])swap(x,y);
int len=dep[x]-dep[tf]+1;
op=0;
y=x;
fd(i,lim,0)
if (len>=(1<<i)){
v[++op]=i;
ss[op]=x;
len-=(1<<i);
x=f[x][i];
}
x=y;
fd(i,op,1){
tog(pt(x,v[i],0),pt(ss[i],v[i],1));
x=f[x][v[i]];
}
}
fd(u,lim,1){
fo(i,1,n){
fo(j,0,1){
int x=pt(i,u,j);
int v=getfather(x);
if (!pd[v]){
pd[v]=1;
q[v]=(x/2-1)%n+1;
p[v]=x%2;
}
else{
int a[2];
a[0]=pt(i,u-1,j);
a[1]=pt(f[i][u-1],u-1,j);
if (p[v]==j){
tog(pt(q[v],u-1,j),a[0]);
tog(pt(f[q[v]][u-1],u-1,j),a[1]);
}
else{
tog(pt(q[v],u-1,j^1),a[1]);
tog(pt(f[q[v]][u-1],u-1,j^1),a[0]);
}
}
}
}
}
fo(i,1,n)tog(pt(i,0,0),pt(i,0,1));
int tt=0;
fo(i,1,n)
if (getfather(i*2)/2==i)tt++;
LL ans=1;
fo(i,1,tt)(ans*=26)%=mo;
printf("%lld\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
附状态,自己找亮点:
我不会提醒你:今天是5.20