dsu on tree
给一棵树,每个节点有一个字母。一些查询Q(x,d),查询x及其子树中,与根节点距离为d的所有字母是否可以构成回文串。
两种思路,dfs序+树状数组或dsu on tree。
dfs序+树状数组
我们可以跑一遍dfs序,这样子树在dfs序中连续。dfs时同时处理出距根所有距离的节点。然后离线询问,按深度排序,开26个树状数组。处理到每一层时将当前层所有节点加入对应字母的树状数组,然后对每个询问的x的dfs序区间进行查询。
复杂度 O(nlog2n) ,cf跑了1400ms,空间102400kb。
dsu on tree
标准dsu on tree板子,每一个深度开个bitset记录字母出现情况,第一次dfs记录深度,第二次dfs更新对应深度的bitset,再做查询。
复杂度 O(nlogn) ,cf跑了1000ms,空间59100kb。优秀啊~
dfs序+树状数组
#include
#define M(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int MAXN=500007;
typedef long long LL;
struct Edge
{
int to, ne;
}e[MAXN];
int head[MAXN], edgenum;
int val[MAXN];char c[MAXN];
int depth[MAXN];
struct Query
{
int id;
int u, dp;
}q[MAXN];
int res[MAXN];
bool cmp(Query a, Query b)
{
return a.dpint dfscount, in[MAXN], ou[MAXN];
int bit[26][MAXN];
vector<int> dp[MAXN];
inline int lowbit(int i) { return i&(-i); }
void change(int i,int pos, int v)
{
while(posint query(int i, int pos)
{
int ans=0;
while(pos>0)
ans+=bit[i][pos], pos-=lowbit(pos);
return ans;
}
void dfs(int u, int fa)
{
in[u]=++dfscount;
if(fa==-1) depth[u]=1;
else depth[u]=depth[fa]+1;
dp[depth[u]].push_back(u);
for(int i=head[u];~i;i=e[i].ne)
dfs(e[i].to, u);
ou[u]=dfscount;
}
int main()
{
int n;
while(scanf("%d", &n)==1)
{
int qam;scanf("%d", &qam);
M(head, -1);edgenum=dfscount=0;
for(int i=2;i<=n;i++)
{
int fa;scanf("%d", &fa);
e[edgenum].to=i, e[edgenum].ne=head[fa], head[fa]=edgenum++;
}
scanf("%s", c+1);
for(int i=1;i<=n;i++)
val[i]=c[i]-'a';
for(int i=1;i<=qam;i++)
{
int t1, t2;scanf("%d%d", &t1, &t2);
q[i].id=i;q[i].u=t1, q[i].dp=t2;
}
dfs(1, -1);
sort(q+1, q+qam+1, cmp);
int cnt=1;
for(int i=1;i<=n;i++)
{
for(int j : dp[i])
{
int c=val[j];
change(c, in[j], 1);
}
while(q[cnt].dp==i)
{
int x=in[q[cnt].u]-1, y=ou[q[cnt].u];
int tmp=0;
for(int k=0;k<26;k++)
{
tmp+=((query(k, y)-query(k, x))%2);
}
res[q[cnt].id]=(tmp<=1);
cnt++;
}
for(int j : dp[i])
{
int c=val[j];
change(c, in[j], -1);
}
}
for(int i=1;i<=qam;i++)
if(res[i]) printf("Yes\n");
else printf("No\n");
}
//system("pause");
return 0;
}
dsu on tree
#include
#define M(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int MAXN=500007;
typedef long long LL;
struct Edge
{
int to, ne;
}e[MAXN];
int head[MAXN], edgenum;
int val[MAXN];char c[MAXN];
int depth[MAXN], sz[MAXN], hson[MAXN];
void dfs(int u, int fa)
{
if(fa==-1) depth[u]=1;
else depth[u]=depth[fa]+1;
sz[u]=1;
for(int i=head[u];~i;i=e[i].ne)
{
int to=e[i].to;
dfs(to, u);
if(!hson[to]) hson[u]=to;
else if(sz[hson[u]]struct Query
{
int id;
int u, dp;
int ne;
}q[MAXN];
int qhead[MAXN], res[MAXN];
int hs;
bitset<26> cnt[MAXN];
void suan(int u, int fa)
{
cnt[depth[u]].flip(val[u]);
for(int i=head[u];~i;i=e[i].ne)
if(e[i].to!=hs)
suan(e[i].to, fa);
}
void dfs(int u, int fa, int kep)
{
for(int i=head[u];~i;i=e[i].ne)
if(e[i].to!=hson[u])
dfs(e[i].to, u, 0);
if(hson[u]) dfs(hson[u], u, 1), hs=hson[u];
suan(u, fa);hs=0;
for(int i=qhead[u];~i;i=q[i].ne)
{
res[q[i].id]=(cnt[q[i].dp].count()<=1);
}
if(!kep) suan(u, fa);
}
int main()
{
int n;
while(scanf("%d", &n)==1)
{
int qam;scanf("%d", &qam);
M(head, -1);edgenum=0;M(qhead, -1);
for(int i=2;i<=n;i++)
{
int fa;scanf("%d", &fa);
e[edgenum].to=i, e[edgenum].ne=head[fa], head[fa]=edgenum++;
}
scanf("%s", c+1);
for(int i=1;i<=n;i++)
val[i]=c[i]-'a';
for(int i=1;i<=qam;i++)
{
int t1, t2;scanf("%d%d", &t1, &t2);
q[i].id=i;q[i].u=t1, q[i].dp=t2, q[i].ne=qhead[t1];qhead[t1]=i;
}
dfs(1, -1);
dfs(1, -1, 0);
for(int i=1;i<=qam;i++)
if(res[i]) printf("Yes\n");
else printf("No\n");
}
//system("pause");
return 0;
}