zoukankan      html  css  js  c++  java
  • #树上启发式合并,位运算#CF570D Tree Requests

    题目

    给定一个以 (1) 为根的 (n) 个结点的树,每个点上有一个字母((a-z)),每个点的深度定义为该节点到 (1) 号结点路径上的点数。

    每次询问 (a, b) 查询以 (a) 为根的子树内深度为 (b) 的结点上的字母重新排列之后是否能构成回文串。


    分析

    回文串最多出现一个奇数次字母,考虑26个字母用位运算的异或,
    (dp[dep])表示以(1)号点为根深度为(dep)的异或值,
    那么这个用树上启发式合并就可以做到(O(nlogn))


    代码

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <vector>
    #define rr register
    using namespace std;
    const int N=500011;
    struct rec{int depth,rk;}; vector<rec>Q[N];
    struct node{int y,next;}e[N]; char s[N];
    int dep[N],fat[N],root,n,siz[N],Qt,big[N],as[N],dp[N],ans[N];
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans;
    }
    inline void dfs1(int x,int fa){
    	dep[x]=dep[fa]+1,fat[x]=fa,siz[x]=1;
    	for (rr int i=as[x],SIZ=-1;i;i=e[i].next){
    		dfs1(e[i].y,x),siz[x]+=siz[e[i].y];
    		if (siz[e[i].y]>SIZ) big[x]=e[i].y,SIZ=siz[e[i].y];
    	}
    }
    inline bool check(int d){return dp[d]==(-dp[d]&dp[d]);}
    inline void update(int x){
        dp[dep[x]]^=1<<(s[x]-97);
    	for (rr int i=as[x];i;i=e[i].next)
    	if (e[i].y!=fat[x]&&e[i].y!=root)
    	    update(e[i].y);
    }
    inline void dfs2(int x,int opt){
    	for (rr int i=as[x];i;i=e[i].next)
    	    if (e[i].y!=fat[x]&&e[i].y!=big[x]) dfs2(e[i].y,0);
    	if (big[x]) dfs2(big[x],1),root=big[x];
    	rr int len=Q[x].size(); update(x);
    	for (rr int i=0;i<len;++i)
    	    ans[Q[x][i].rk]=check(Q[x][i].depth);
    	if (!opt) root=0,update(x);
    }
    signed main(){
    	n=iut(),Qt=iut();
    	for (rr int i=2;i<=n;++i){
    		rr int x=iut();
    		e[i]=(node){i,as[x]},as[x]=i;
    	}
    	scanf("%s",s+1),dfs1(1,0);
    	for (rr int i=1;i<=Qt;++i){
    		rr int x=iut(),h=iut();
    		Q[x].push_back((rec){h,i});
    	}
    	dfs2(1,0);
    	for (rr int i=1;i<=Qt;++i)
    	    puts(ans[i]?"Yes":"No");
    	return 0;
    }
    
  • 相关阅读:
    我回来了
    wget 官方jdk
    linux rpm命令安装卸载 初步使用
    关于一些对location认识的误区(转)
    直接插入排序
    冒泡排序
    Wireshark下TCP三次握手四次挥手
    linux内存使用率详解
    Linux下硬盘使用率详解及shell脚本实现
    Linux下CPU使用率详解
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14980652.html
Copyright © 2011-2022 走看看