• 题解 弋或树


    题目描述

    题目链接

    题解

    写在前面

    弋(yì)或树 异或树

    前置知识

    为了解决本题,你应该要会

    • Trie树模板
    • Trie树二进制表示数

    思路

    解法一

    我会暴力!
    最坏情况下时间复杂度为(O(nm))
    得分:(29)
    好水啊

    解法water

    我会Trie树!
    预处理所有子树异或和,加入Trie树,直接二进制查找。
    得分:(0)
    这件事情告诉我们暴力比乱搞好用

    解法二

    我会修改Trie树模板!

    观察本题后发现本题难点在于如何(O(logx))求出以u为根的子树下某一个子树的异或和

    思考后发现可以选择在Trie树内记录 Trie树每个节点 所对应的 题目给出的树的节点,再lca(O(logn))查询是否有祖先关系即可

    然而当所有子树异或和相同时 Trie树每个节点 所对应的 题目给出的树的节点 可以达到(n)个,总的时间复杂度为(O(m imes logx imes n imes logn))
    得分:(29)

    解法三

    我会建多个Trie树!
    即对于每个节点都建一个Trie树
    然而当树退化为链时,建树时间复杂度可以达到(O(logxn^2)),空间复杂度为(O(n^2))
    得分:(0)

    解法四

    我会离线处理!

    对于解法三,我们发现父节点的Trie树其实是由子节点的Trie树决定的

    所以说可以考虑先求出叶子节点,再一层一层将Trie树上移
    即先求出儿子节点的Trie树,处理完儿子节点的询问,再将其中儿子节点的Trie树拓展到其父亲的Trie树(加入其它子节点即父节点),重复此步骤

    这样,当询问的点要么基本覆盖整棵树时,拓展的效率会比较高,当重复较多时,多次处理效率也较高,不过最坏时间复杂度似乎有点难估算

    具体算法实现步骤为
    (以下将有询问的节点统称为询问节点)

    1.预处理
    2.找到询问节点u
    3.对于每个询问节点u,先找到询问节点u的子树中 子树节点数量最多的询问子节点v
    4.并将询问节点u的子树中其他节点加入询问节点v的Trie树中
    5.将询问节点u的询问全部处理

    代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    int n,m,a[100005],x[100005],s[100005],d[100005];
    struct que {
    	int x,id;
    } ans[100005];
    vector<que>q[100005];
    vector<int>g[100005];
    void dfs(int u,int fa) {//步骤1
    	s[u]=1,x[u]=a[u];
    	for(int i=0; i<g[u].size(); i++) {
    		int v=g[u][i];
    		if(v==fa)continue;
    		dfs(v,u);
    		s[u]=s[u]+s[v],x[u]=x[u]^x[v];
    	}
    }
    struct trie {
    	vector<int*>c;
    	int tot;
    	void build() {
    		tot=0;
    		c.clear(),c.push_back(NULL);
    	}
    	void insert(int x) {
    		int p=0;
    		for(int i=30; i>=0; i--) {
    			int v=((x&(1<<i))>>i);
    			if(c[p]==NULL) {
    				c[p]=new int[2];
    				memset(c[p],-1,sizeof(int)*2);
    			}
    			if(c[p][v]==-1) {
    				c[p][v]=++tot;
    				c.push_back(NULL);
    			}
    			p=c[p][v];
    		}
    	}
    	int find(int x) {
    		int p=0;
    		for(int i=30; i>=0; i--) {
    			int v=((x&(1<<i))>>i);
    			if(c[p][v^1]==-1)p=c[p][v];
    			else p=c[p][v^1],x=(x^(1<<i));
    		}
    		return x;
    	}
    } tr[100005];
    int b,t,y;
    void xun(int u,int fa) {//步骤3
    	if(q[u].size()>0) {
    		if(s[u]>s[b])b=u;
    		return;
    	}
    	for(int i=0; i<g[u].size(); i++) {
    		int v=g[u][i];
    		if(v==fa)continue;
    		xun(v,u);
    	}
    }
    void zhao(int u,int fa) {//步骤4
    	if(u==b)return;
    	tr[y].insert(x[u]);
    	for(int i=0; i<g[u].size(); i++) {
    		int v=g[u][i];
    		if(v==fa)continue;
    		zhao(v,u);
    	}
    }
    void check(int u,int fa) {//步骤2
    	for(int i=0; i<g[u].size(); i++) {
    		int v=g[u][i];
    		if(v==fa)continue;
    		check(v,u);
    	}
    	if(q[u].size()>0) {
    		b=0;//步骤3
    		for(int i=0; i<g[u].size(); i++) {
    			int v=g[u][i];
    			if(v==fa)continue;
    			xun(v,u);
    		}
    		if(b==0)d[u]=t++,tr[d[u]].build();
    		else d[u]=d[b];
    		y=d[u];
    		zhao(u,fa);//步骤4
    	}
    	for(int i=0; i<q[u].size(); i++) {//步骤5
    		ans[m].id=q[u][i].id;
    		ans[m--].x=q[u][i].x^tr[d[u]].find(q[u][i].x);
    	}
    }
    bool cmp(que a1,que b1) {
    	return a1.id<b1.id;
    }
    inline int read() {
    	int s=0;
    	char ch=getchar();
    	while(ch<'0'||ch>'9')ch=getchar();
    	while(ch>='0'&&ch<='9') {
    		s=s*10+ch-'0';
    		ch=getchar();
    	}
    	return s;
    }
    int main() {
    	n=read(),m=read();
    	for(int i=1; i<=n; i++)a[i]=read();
    	for(int i=1; i<n; i++) {
    		int u=read(),v=read();
    		g[u].push_back(v);
    		g[v].push_back(u);
    	}
    	for(int i=1; i<=m; i++) {
    		int u=read(),x=read();
    		q[u].push_back((que){x,i});
    	}
    	dfs(1,0);
    	check(1,-1);
    	sort(ans+1,ans+1+n,cmp);
    	for(int i=1; i<=n; i++)printf("%d
    ",ans[i].x);
    	return 0;
    }
    
  • 相关阅读:
    获取目录下所有文件名
    毕业论文endnote使用
    CoinChange
    sublime3个人配置
    2015-12-31
    2015-12-09
    #define DEBUG用法
    fiddler介绍
    app测试模块
    android SDK_安装配置_使用
  • 原文地址:https://www.cnblogs.com/ezlmr/p/12288605.html
Copyright © 2020-2023  润新知