【算法练习】CodeForces570D Tree Requests(树上启发合并)

题意

给定一棵树,树上每个节点上有一个小写字符,给出一些询问,询问包括节点和深度,求出以这个节点为固定深度的节点上能否组成一个回文串。

题解

子树静态的问题,所以考虑树上启发合并,其实就是如何维护答案。
首先考虑回文串出现的条件,组成回文串的所有字母中奇数个的字母不超过1个。
由于总的字母类别不超过26个,我们可以利用二进制的思想,即每一个字母对应二进制的一位,若一个字母出现奇数次,那么该位为1,反之为0.
如果加入一个字母,则将当前的状态与字母对应的二进制位做异或即可,最后统计1的个数。这里可以使用位运算或者bitset维护。
下面考虑如何统计答案,首先要有记录深度, c n t [ x ] 表示深度为x当前子树的状态。如果要加入当前节点的答案,直接按照上面的方法异或就好了,如果要删除,其实也是按照上面的方法异或一次。
算一个二进制中1的个数,如果用bitset,那么直接b.count()就完事了,如果用位运算,可以参考下面的代码。

代码

#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
struct edge{int to,nxt;}e[nmax<<1];
struct node2{int to,nxt; bool ans;}query[nmax];
int n,m,tot,head[nmax],deep[nmax],sz[nmax],son[nmax];
int qhead[nmax],num;
int cnt[nmax],nowadd;
bool visit[nmax];
char letter[nmax];
void add(int u, int v) {e[tot].to = v; e[tot].nxt = head[u]; head[u] = tot++;}
void add_query(int vertex, int deep) {
    query[num].to = deep, query[num].nxt = qhead[vertex], qhead[vertex] = num++;
}
inline bool countone(int n){
    int count = 0;
    while(n) {n &= (n-1); count++; if(count > 1) return false; }
    return true;
}
void dfs1(int u, int f, int d){
    deep[u] = d; sz[u] = 1;
    for(int i = head[u];i!=-1;i = e[i].nxt){
        int v = e[i].to;
        if(v != f){
            dfs1(v,u,d+1);
            sz[u] += sz[v];
            if(sz[v] > sz[son[u]]) son[u] = v;
        }
    }
}
void update(int u, int f){
    cnt[deep[u]] ^= (1<<(letter[u] - 'a'));
    for(int i = head[u];i!=-1;i=e[i].nxt){
        int v = e[i].to;
        if(v != f && !visit[v]) update(v,u);
    }
}
void dfs2(int u, int f, bool keep = false) {
    for(int i = head[u];i!=-1;i = e[i].nxt){
        int v = e[i].to;
        if(v == f || v == son[u]) continue;
        else dfs2(v,u);
    }
    if(son[u]) dfs2(son[u],u,true), visit[son[u]] = true;
    update(u,f);
    for(int i = qhead[u] ;i!=-1;i = query[i].nxt)query[i].ans = countone(cnt[query[i].to]);
    if(son[u]) visit[son[u]] = false;
    if(!keep) update(u,f);
}
int main(){
    memset(head,-1,sizeof head);
    memset(qhead,-1,sizeof qhead);
    scanf("%d %d",&n,&m);
    int v;
    for(int u = 2;u<=n;++u){
        scanf("%d",&v);
        add(u,v), add(v,u);
    }
    scanf("%s",letter + 1);
    int vertex, dee;
    for(int i = 1;i<=m;++i) {
        scanf("%d %d",&vertex,&dee);
        add_query(vertex,dee);
    }
    dfs1(1,-1,1);
    dfs2(1,-1);
    for(int i = 0;i<m;++i) printf("%s\n",query[i].ans == true?"Yes":"No");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/pengwill97/article/details/81434073