列表

详情


NC22527. 异或树

描述

有一棵n个节点的异或树,1号点为根,每个节点有一个权值w_i。每次询问给出u,x,询问子树u内,点的权值大于x的所有权值异或x的和。即
由于这是一棵异或树,所以,如果一个数出现了两次,那么这两个点的权值就消失了(点并没有消失,即树的形态没有发生变化,只是在计算时忽略这两个点的权值。)消失过程发生在一次询问时,如果子树内两个点的权值一样,那么这两个点的权值同时消失,直到无法再有点对消失后查询。

输入描述

第一行两个整数n,Q,分别表示点的个数和询问个数。
第二行n个整数w_i
第二行到第n行,每行两个整数,描述一条边u,v。
接下来q行,每行两个整数u,x,描述一次询问。

输出描述

对于每次询问,输出一个整数表示答案。

示例1

输入:

6 5
2 3 4 2 3 3
1 2
2 3
2 4
2 5
1 6
1 1
1 4
2 1
2 3
6 1

输出:

7
0
8
7
2

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 541ms, 内存消耗: 158184K, 提交时间: 2019-03-19 11:56:22

#include<bits/stdc++.h>
#define lson ls[x],l,mid
#define rson rs[x],mid+1,r
using namespace std;const int N=1e5+7,M=N*20;long long ans[N];
struct data{int to,next;}e[N<<1];int root[N],ls[M],bit[M][18],Bit[18],Size,rs[M],size[M],a[N],head[N],sz,u,v,cnt,n,m,i,j;vector<int>vec[N];
void ins(int u,int v){e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;}
void insert(int u,int v){ins(u,v);ins(v,u);}
void update(int x){
	size[x]=size[ls[x]]+size[rs[x]];
	for(int i=0;i<=17;++i)bit[x][i]=bit[ls[x]][i]+bit[rs[x]][i];
}
int merge(int x,int l,int r,int y){
	if(!x||!y)return x+y;if(l==r)return 0;int mid=l+r>>1;
	ls[x]=merge(lson,ls[y]);rs[x]=merge(rson,rs[y]);
	update(x);return x;
}
void update(int&x,int l,int r,int pos){
	if(!x)x=++sz;size[x]++;for(int i=0;i<=17;++i)bit[x][i]+=pos>>i&1;if(l==r)return;int mid=l+r>>1;
	if(pos<=mid)update(lson,pos);else update(rson,pos);update(x);
} 
void query(int x,int l,int r,int a,int b){
	if(a<=l&&r<=b||!x){for(int i=0;i<=17;++i)Bit[i]+=bit[x][i];Size+=size[x];return;};int mid=l+r>>1;
	if(a<=mid)query(lson,a,b);if(b>mid)query(rson,a,b);
}
void dfs(int x,int fa=0){
	update(root[x],1,n+1,a[x]);
	for(int i=head[x];i;i=e[i].next)if(e[i].to!=fa)dfs(e[i].to,x),root[x]=merge(root[x],1,n+1,root[e[i].to]);
	for(int i=0,id,num;i<vec[x].size();i+=2){
		num=vec[x][i];id=vec[x][i+1];Size=0;memset(Bit,0,sizeof(Bit));
		query(root[x],1,n+1,num+1,n+1);
		for(int j=0;j<=17;++j)ans[id]+=((num>>j&1)?(Size-Bit[j]):Bit[j])*(1LL<<j);
	}
}
int main(){
	for(scanf("%d%d",&n,&m),i=1;i<=n;++i)scanf("%d",a+i);
	for(i=1;i<n;++i)scanf("%d%d",&u,&v),insert(u,v);
	for(i=1;i<=m;++i)scanf("%d%d",&u,&v),vec[u].push_back(v),vec[u].push_back(i);
	for(dfs(1),i=1;i<=m;++i)printf("%lld\n",ans[i]);
}

C++11(clang++ 3.9) 解法, 执行用时: 733ms, 内存消耗: 276312K, 提交时间: 2019-02-09 11:48:11

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
int gi(){
	int x=0,w=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')w=0,ch=getchar();
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
const int N=1e5+5;
const int M=4e6+5;
int n,q,w[N],ls[M],rs[M],sz[M],cnt[M][17],rt[N],tot,Sz,Cnt[17];
vector<int>E[N];
void up(int x){
	sz[x]=sz[ls[x]]+sz[rs[x]];
	for(int i=0;i<17;++i)cnt[x][i]=cnt[ls[x]][i]+cnt[rs[x]][i];
}
void modify(int &x,int l,int r,int p){
	x=++tot;
	if(l==r){
		for(int i=0;i<17;++i)cnt[x][i]=p>>i&1;
		sz[x]=1;return;
	}
	int mid=l+r>>1;
	p<=mid?modify(ls[x],l,mid,p):modify(rs[x],mid+1,r,p);
	up(x);
}
int merge(int x,int y,int l,int r){
	if(!x||!y)return x|y;if(l==r)return 0;
	int mid=l+r>>1,z=++tot;
	ls[z]=merge(ls[x],ls[y],l,mid);
	rs[z]=merge(rs[x],rs[y],mid+1,r);
	up(z);return z;
}
void query(int x,int l,int r,int ql,int qr){
	if(l>=ql&&r<=qr){
		for(int i=0;i<17;++i)Cnt[i]+=cnt[x][i];
		Sz+=sz[x];return;
	}
	int mid=l+r>>1;
	if(ql<=mid)query(ls[x],l,mid,ql,qr);
	if(qr>mid)query(rs[x],mid+1,r,ql,qr);
}
void dfs(int u,int f){
	modify(rt[u],1,n,w[u]);
	for(int v:E[u])if(v^f)dfs(v,u),rt[u]=merge(rt[u],rt[v],1,n);
}
int main(){
	n=gi();q=gi();
	for(int i=1;i<=n;++i)w[i]=gi();
	for(int i=1;i<n;++i){
		int u=gi(),v=gi();
		E[u].push_back(v);E[v].push_back(u);
	}
	dfs(1,0);
	while(q--){
		int u=gi(),x=gi();
		for(int i=0;i<17;++i)Cnt[i]=0;Sz=0;
		if(x<n)query(rt[u],1,n,x+1,n);
		long long ans=0;
		for(int i=0;i<17;++i)ans+=1ll*((x>>i&1)?Sz-Cnt[i]:Cnt[i])<<i;
		printf("%lld\n",ans);
	}
	return 0;
}

上一题