• 【题解】CF570D Tree Requests


    Problem

    ( ext{Solution:})

    如果一个字符串重排可以构成回文串那么其中出现次数为奇数次的字符一定不超过一个。

    第一种思路:对每一个点,每一种颜色分别维护一个权值线段树,以深度为序建立,每次 (|E|) 次查询即可。( (|E|) 是字符集大小)

    战绩: (color{purple}{ ext{TLE on test41}})

    (|E|) 大小的时空常数被卡的死死的。

    第二种思路:考虑将字母状压成一个二进制数。那么,每次在深度上加入一个数,我们可以用 异或 操作来获得当前位置上字母的奇偶性。最后查询出现次数是奇数的字符即可。

    那么合并的时候维护信息应该用异或的操作。线段树合并复杂度 (O(nlog n).)

    战绩: (color{red}{ ext{MLE on test48}})

    观察数据发现是一条链,会把空间卡满。改了半天发现是空间回收炸掉了……

    删掉空间回收,把空间压到极限 ((10^6)) 最终消耗空间 (249.24MB). vector 的实现改用了链表。

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> pr;
    const int MAXN=10000010;
    const int N=5e5+10;
    int sum[MAXN];
    int dep[N],pa[N],ls[MAXN],n,m;
    int rs[MAXN],node,tot,head[N];
    int val[N],Maxdep;
    struct E{int nxt,to;}e[N];
    struct List{
    	int nxt;
    	pair<int,int>v;
    }vt[N];
    int Head[N],cnt;
    void add_query(int pos,pair<int,int> v){
    	vt[++cnt]=(List){Head[pos],v};
    	Head[pos]=cnt;
    }
    bool ans[N];
    inline int Max(int x,int y){return x>y?x:y;}
    inline int read(){
    	int s=0;
    	char ch=getchar();
    	while(!isdigit(ch)) ch=getchar();
    	while(isdigit(ch)){
    		s=s*10-48+ch;
    		ch=getchar();
    	}
    	return s;
    }
    inline void add(int x,int y){e[++tot]=(E){head[x],y};head[x]=tot;} 
    struct Tree{
    	int rt;
    	inline void pushup(int x){sum[x]=sum[ls[x]]^sum[rs[x]];}
    	void change(int &x,int L,int R,int pos,int v){
    		if(!x)x=++node;
    		if(L==R){
    			sum[x]+=v;
    			return;
    		}
    		int mid=(L+R)>>1;
    		if(pos<=mid)change(ls[x],L,mid,pos,v);
    		else change(rs[x],mid+1,R,pos,v);
    		pushup(x);
    	}
    	int merge(int x,int y,int l,int r){
    		if(!x||!y)return x+y;
    		if(l==r){sum[x]^=sum[y];return x;}
    		int mid=(l+r)>>1;
    		ls[x]=merge(ls[x],ls[y],l,mid);
    		rs[x]=merge(rs[x],rs[y],mid+1,r);
    		pushup(x);return x;
    	}
    	int query(int x,int L,int R,int pos){
    		if(L==R)return sum[x];
    		int mid=(L+R)>>1;
    		if(pos<=mid)return query(ls[x],L,mid,pos);
    		return query(rs[x],mid+1,R,pos);
    	}
    }tr[MAXN];
    void dfs(int x){
    	for(int i=head[x];i;i=e[i].nxt){
    		int j=e[i].to;
    		dep[j]=dep[x]+1;
    		Maxdep=Max(Maxdep,dep[j]);
    		dfs(j);
    	}
    }
    char s[N];
    void dfs_merge(int x){
    	tr[x].change(tr[x].rt,1,Maxdep,dep[x],val[x]);
    	for(int i=head[x];i;i=e[i].nxt){
    		int j=e[i].to;
    		dfs_merge(j);
    		tr[x].rt=tr[x].merge(tr[x].rt,tr[j].rt,1,Maxdep);
    	}
    	for(int i=Head[x];i;i=vt[i].nxt){
    		pr j=vt[i].v;
    		int ct=0;
    		int sv=0;
    		sv=tr[x].query(tr[x].rt,1,Maxdep,j.first);
    		for(int j=1;j<=26;++j){if(sv&(1<<j))ct++;}
    		if(ct<=1||j.first<dep[x]||j.first>Maxdep)ans[j.second]=1;
    		else ans[j.second]=0;
    	}
    }
    int main(){
    	n=read();m=read();
    	if(n==1){
    		for(int i=1;i<=m;++i)puts("Yes");
    		return 0;
    	}
    	for(int i=2;i<=n;++i){
    		pa[i]=read();
    		add(pa[i],i);
    	}
    	dep[1]=1;dfs(1);
    	scanf("%s",s+1);
    	for(int i=1;i<=n;++i){val[i]=(1<<(s[i]-'a'+1));}
    	for(int i=1;i<=m;++i){
    		int a=read(),b=read();
    		add_query(a,make_pair(b,i));
    	}
    	dfs_merge(1);
    	for(int i=1;i<=m;++i){
    		if(ans[i]==1)puts("Yes");
    		else puts("No");
    	}
    	return 0;
    }
    
  • 相关阅读:
    阿里云esc 安装 mysql8.0
    阿里云esc 登录时的相关提示
    C# web项目 log4net 使用
    MVC 全局异常捕获
    datetimepicker 基础使用/select2 基础使用
    C# 从登陆开始 MVC4+BOOTSTRAP
    Android如何导入语言资源
    Android自带邮件含中文的附件用HTML打开乱码问题的解决
    android 解决输入法遮挡输入框的问题
    repo代码简单解读
  • 原文地址:https://www.cnblogs.com/h-lka/p/14961858.html
Copyright © 2020-2023  润新知