• CF570D Tree Requests


    洛咕

    题意:给定一个以1为根的n个节点的树,每个点上有一个字母((a-z)),每个点的深度定义为该节点到1号节点路径上的点数.每次询问 (a,b) 查询以(a)为根的子树内深度为(b)的节点上的字母重新排列之后是否能构成回文串.(n,m<=500000.)

    分析:还是那个模板,然后一个子树内的字母重新排列之后要能够构成回文串,当且仅当出现次数为奇数个的字母至多只有一个.根据这个性质,我们可以用二进制位来表示每个字母,即每个节点赋上权值(1<<(ch-'a')),然后合并的时候就把权值异或起来就好了.最后就只要计算这个数是否只有最多一位为1就好了.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=500005;
    int n,m,visit[N],ans[N];char s[N];
    int size[N],son[N],sum[N],val[N],dep[N];
    int tot,head[N],nxt[N],to[N];
    inline void add(int a,int b){
    	nxt[++tot]=head[a];head[a]=tot;to[tot]=b;
    }
    struct node{int h,nxt;}a[N];int Head[N];
    inline void Add(int v,int h,int id){
        a[id]=(node){h,Head[v]};Head[v]=id;
    }
    inline void pre_dfs(int u){
    	size[u]=1;
    	for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];dep[v]=dep[u]+1;
    		pre_dfs(v);size[u]+=size[v];
    		if(size[v]>size[son[u]])son[u]=v;
    	}
    }
    inline void update(int u){
    	sum[dep[u]]^=val[u];//异或和a
    	for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];if(visit[v])continue;
    		update(v);
    	}
    }
    inline bool calc(int x){//计算这个数为1的位有多少个
    	int cnt=0;
    	for(int i=0;i<=25;++i)if(x&(1<<i))++cnt;
    	return cnt<=1;
    }
    inline void dfs(int u,int keep){
    	for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];if(son[u]==v)continue;
    		dfs(v,0);
    	}
    	if(son[u])dfs(son[u],1),visit[son[u]]=1;update(u);
    	for(int i=Head[u];i;i=a[i].nxt)ans[i]=calc(sum[a[i].h]);
    	visit[son[u]]=0;if(!keep)update(u);
    }
    int main(){
    	n=read(),m=read();
    	for(int i=2;i<=n;++i){int x=read();add(x,i);}//直接建有向边
    	scanf("%s",s+1);for(int i=1;i<=n;++i)val[i]=1<<(s[i]-'a');//给节点赋权值
    	for(int i=1,v,h;i<=m;++i)v=read(),h=read(),Add(v,h,i);//把询问离线
    	dep[1]=1;//刚开始这里没赋值,调了两个小时
        pre_dfs(1);dfs(1,1);for(int i=1;i<=m;++i)puts(ans[i]?"Yes":"No");
        return 0;
    }
    
    
  • 相关阅读:
    用goto做异常处理
    零长度数组的妙用
    DTMF三种模式(SIPINFO,RFC2833,INBAND)
    Myeclipse下的struts2.3.8 配置 保证绝对好用
    Linux内核--内核数据类型
    Linux内核:kthread_create(线程)、SLEEP_MILLI_SEC
    3.4.4 数据预留和对齐(skb_reserve, skb_push, skb_put, skb_pull)
    Linux 2.6内核中新的锁机制--RCU
    Linux中SysRq的使用(魔术键)
    CentOS Linux服务器安全设置
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11666796.html
Copyright © 2020-2023  润新知