BZOJ4568 [Scoi2016]幸运数字

BZOJ4568 [Scoi2016]幸运数字


题目描述

传送门

题目分析

这个题,求树上链的\(XOR\)最大值,可以不选某些点。

考虑到线性基可以用很快的速度求出\(XOR\)的最大值,我们首先可以确定使用线性基来搞定这个题的询问。

然后可以考虑用树剖解决,发现一个问题,使用树剖时,由于一边跳一遍计算线性基,还要合并,复杂度比较高,虽然的确可以通过本题,但是明显可以通过随便增大数据就卡死了。倍增貌似拥有更好的常数,但是,空间利用太低,容易\(MLE\)

发现每次询问只询问链,那么我们可以使用LCT点分治来解决这个题。

具体方法就是,我们点分治计算每个子树的时候,把询问中lca是这个子树的根的直接求出来然后合并,不是的就把询问传下去,这样复杂度就是\(O(Nlog^2N)\)的,非常优秀可以通过。

是代码呢

#include <bits/stdc++.h>
using namespace std;
const int MAXN=2e5+7;
#define ll long long
const ll inf=1ll<<61;
ll n,m,a[MAXN],p[MAXN],ans[MAXN],size[MAXN],wson[MAXN],vis[MAXN],U[MAXN],V[MAXN],bel[MAXN],tq[MAXN],sum,root;
bool use[MAXN];
inline ll read()
{
    ll x=0,c=1;
    char ch=' ';
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    while(ch=='-')c*=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*c;
}
vector<int> edge[MAXN],q[MAXN];
struct T{
	ll b[65];
	inline void clear() {memset(b,0,sizeof(b));}
	inline void insert(ll x){
		for(int i=60;~i;i--)
			if(x>>i&1){
				if(b[i]) x^=b[i];
				else {b[i]=x;break;}
			}
	}
	inline void merge(const T &x){
		for(int i=60;~i;i--){
			if(x.b[i]) insert(x.b[i]);
		}
	}
	inline ll query(){
		ll ans=0;
		for(int i=60;~i;i--){
			if((ans^b[i])>ans) ans^=b[i];
		}
		return ans;
	}
}base[MAXN];
inline void get_root(int u,int fa)
{
	size[u]=1;wson[u]=0;
	for(int i=0;i<edge[u].size();i++){
		int v=edge[u][i];
		if(v==fa||vis[v]) continue;
		get_root(v,u);
		size[u]+=size[v];
		if(wson[u]<size[v]) wson[u]=size[v];
	}
	if(sum-size[u]>wson[u]) wson[u]=sum-size[u];
	if(wson[u]<wson[root]) root=u;
}

inline void dfs(int u,int fa,int tt){
	base[u]=base[fa]; bel[u]=tt;base[u].insert(a[u]);
	for(int i=0;i<edge[u].size();i++){
		int v=edge[u][i];
		if(v!=fa&&!vis[v]) dfs(v,u,tt);
	}
}

inline void solve(int x){
	if(!q[x].size()) return;
	wson[0]=inf;sum=size[x];root=0;
	get_root(x,0);
	int u=root;
	vis[root]=1;bel[root]=root;
	base[root].clear();base[root].insert(a[root]);
	for(int i=0;i<edge[root].size();i++){
		int v=edge[root][i];
		if(!vis[v]) dfs(v,root,v);
	}
	int tot=q[x].size();
	for(int i=0;i<tot;i++) tq[i]=q[x][i];
	q[x].clear();
	T tmp;ll id;
	for(int i=0;i<tot;i++){
		id=tq[i];
		if(bel[U[id]]==bel[V[id]])
			q[bel[U[id]]].push_back(id);
		else tmp=base[U[id]],tmp.merge(base[V[id]]),ans[id]=tmp.query(),use[id]=1;
	}
	for(int i=0;i<edge[u].size();i++){
		int v=edge[u][i];
		if(vis[v]) continue;
		solve(v);
	}
}
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();
		edge[u].push_back(v);
		edge[v].push_back(u);
	}
	for(int i=1;i<=m;i++){
		U[i]=read();V[i]=read();
		if(U[i]==V[i]) ans[i]=a[U[i]];
		else q[1].push_back(i);
	}
	size[1]=n;solve(1);
	for(int i=1;i<=m;i++) printf("%lld\n", ans[i]);
}
posted @ 2019-01-16 16:58  ~victorique~  阅读(152)  评论(0编辑  收藏  举报
Live2D