! TJOI2018xor


思考:

1问:像线段树合并一样合并trie树

2问:点分治或者直接暴力路径上trie树

题解说可持久化01trie咋又去看题解了

想想,像树链剖分一样,只不过把查询移到trie上

时间复杂度\(O(nlog^2)\)

链查询的复杂度是高了些

再来一个01trie表示到根的路径差分一下

时间复杂度\(O(nlog)\)

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int N=1e5+4;
struct _01trie{
	int ch[N<<5][2],tg[N<<5],tot;
	inline void insert(int p,int pre,int x){
		for(int i=30,c;i>=0;i--){
			c=(x>>i)&1;
			ch[p][c^1]=ch[pre][c^1];
			if(!ch[p][c])ch[p][c]=++tot;
			p=ch[p][c];pre=ch[pre][c];
			tg[p]=tg[pre]+1;
		}
	}
	inline int query(int pl,int pr,int x){
		int ret=0;
		for(int i=30,c;i>=0;i--){
			c=(x>>i)&1;
			if(tg[ch[pr][c^1]]-tg[ch[pl][c^1]]){
				ret|=(1<<i);
				pl=ch[pl][c^1];pr=ch[pr][c^1];
			}
			else{pl=ch[pl][c];pr=ch[pr][c];}
		}
		return ret;
	}
}t1,t2;
int n,Q,tim,dep[N],st[N],ed[N],pos[N],a[N],fa[N][20];
vector<int>e[N];
void dfs(int x){
	t1.insert(x,fa[x][0],a[x]);
	st[x]=++tim;pos[tim]=x;
	dep[x]=dep[fa[x][0]]+1;
	for(int i=1;(1<<i)<=dep[x];i++)
		fa[x][i]=fa[fa[x][i-1]][i-1];
	for(auto v:e[x])
		if(v!=fa[x][0]){
			fa[v][0]=x;
			dfs(v);
		}
	ed[x]=tim;
}
inline int getlca(int u,int v){
	if(dep[u]<dep[v])u^=v^=u^=v;
	for(int i=17;i>=0;i--)
		if(dep[fa[u][i]]>=dep[v])u=fa[u][i];
	if(u==v)return u;
	for(int i=17;i>=0;i--)
		if(fa[u][i]!=fa[v][i]){
			u=fa[u][i];v=fa[v][i];
		}
	return fa[u][0];
}
int main(){
	t1.tot=t2.tot=n=read();Q=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1,u,v;i<n;i++){
		u=read();v=read();
		e[u].push_back(v);e[v].push_back(u);
	}
	dfs(1);
	for(int i=1;i<=n;i++)t2.insert(i,i-1,a[pos[i]]);
	while(Q--){
		static int op,x,y,z,lca;
		op=read();x=read();y=read();
		if(op==1)cout<<t2.query(st[x]-1,ed[x],y)<<"\n";
		else{
			lca=getlca(x,y);
			z=read();
			cout<<max(t1.query(lca,x,z),t1.query(fa[lca][0],y,z))<<"\n";
		}
	}
	return (0-0);
}

猜你喜欢

转载自www.cnblogs.com/aurora2004/p/12624444.html
今日推荐