2019.01.01【SCOI2016】【BZOJ4568】【洛谷P3292】幸运数字(线性基)(点分治)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/85568253

BZOJ传送门

洛谷传送门


解析:

第一眼倍增+线性基合并 O ( ( n + m ) log n log 2 G i ) O((n+m)\log n\log^2|G_i|) ,复杂度过不了。
第二眼树分块+线性基合并 O ( ( n + m ) n log 2 G i ) O((n+m)\sqrt n\log^2|G_i|) ,复杂度过不了。

算了写点分治吧。。。

思路:

子集最大异或和,显然线性基。
线性基的合并似乎也没有什么快的算法,就暴力合并吧, O ( log 2 G i ) O(\log^2 |G_i|)

要是倍增再来一个 O ( log G i ) O(\log|G_i|) 就真GG了。

所以我们不用倍增,考虑怎么拼出一条路径,对,点分治。

复杂度期望 O ( n log n log G i + m log 2 G i ) O(n\log n\log |G_i|+m\log^2|G_i|) ,不过好像最坏情况也是这个,我就不证明了。

每次选择一个重心,处理出当前联通块中所有点到它的路径的线性基。

然后所有在这个联通块里面的询问,看是否两个端点不在同一个子树内部。不在的话就可以合并它们的线性基,不需要担心根节点权值的问题,因为一个线性基里面多次插入一个值是不会有任何影响的。

然后直接在线性基里面查询最大值。直接从最高位贪心做就行了。

实际实现的时候我加了很多剪枝,不过很多似乎没优化啊。。。


UPD:

去看了一下题解,几乎全部都是倍增。。。

是这数据真是水的可以,还是我的复杂度分析错了啊。。。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc put_char
#define cs const

namespace IO{
	namespace IOONLY{
		cs int Rlen=1<<18|1;
		char buf[Rlen],*p1,*p2;
		char obuf[Rlen],*p3=obuf;
		char ch[23];
	}
	inline char get_char(){
		using namespace IOONLY;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	inline void put_char(char c){
		using namespace IOONLY;
		*p3++=c;
		if(p3==obuf+Rlen)fwrite(obuf,1,Rlen,stdout),p3=obuf;
	}
	inline void FLUSH(){
		using namespace IOONLY;
		fwrite(obuf,1,p3-obuf,stdout),p3=obuf;
	}
	
	inline ll getint(){
		re ll num;
		re char c;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	inline void outint(ll a){
		using namespace IOONLY;
		if(a==0)return pc('0');
		while(a)ch[++ch[0]]=a-a/10*10,a/=10;
		while(ch[0])pc(ch[ch[0]--]^48);
	}
}
using namespace IO;

namespace Linear_base{
	inline void clear(ll f[]){
		memset(f,0,sizeof(ll)*61);
	}
	
	inline void copy(ll g[],ll f[]){
		memcpy(g,f,sizeof(ll)*61);
	}
	
	inline void insert(ll f[],ll a){
		for(int re i=60;~i;--i){
			if(a&(1ll<<i)){
				if(!f[i]){
					f[i]=a;
					return ;
				}
				a^=f[i];
				if(a==0)return ;
			}
		}
	}
	
	inline void merge(ll g[],ll f1[],ll f2[]){
		copy(g,f1);
		for(int re i=60;~i;--i){
			if(f2[i]&&(f2[i]^f1[i])&&(f2[i]^g[i]))insert(g,f2[i]);
		}
	}
	
	inline ll query(ll f[],ll res=0){
		for(int re i=60;~i;--i)if((res^f[i])>res)res^=f[i];
		return res;
	}
}

cs int N=20004,Q=200005,B=61;
vector<int> edge[N];
inline void addedge(int u,int v){
	edge[v].push_back(u);
	edge[u].push_back(v);
}

ll g[N];
int last[N],nxt[Q<<1],to[Q<<1],qcnt=1; 
bool have[Q];ll ans[Q];
inline void addq(int u,int v){
	nxt[++qcnt]=last[u],last[u]=qcnt,to[qcnt]=v;
	nxt[++qcnt]=last[v],last[v]=qcnt,to[qcnt]=u;
	if(u==v)have[qcnt>>1]=true,ans[qcnt>>1]=g[u];
}

int n,q;
bool ban[N];
int que[N],siz[N],tail;
int total,mx,G;
inline void find_G(int u,int fa){
	while(last[u]&&have[last[u]>>1])last[u]=nxt[last[u]];
	if(last[u])que[++tail]=u;
	siz[u]=1;int maxn=1;
	for(int re e=0;e<edge[u].size();++e){
		if(ban[edge[u][e]])continue;
		if(edge[u][e]^fa){
			find_G(edge[u][e],u);
			siz[u]+=siz[edge[u][e]];
			maxn=max(maxn,siz[edge[u][e]]);
		}
	}
	maxn=max(maxn,total-siz[u]);
	if(mx>=maxn){
		mx=maxn;
		G=u;
	}
}

int group[N],tsiz[N];;
ll res[B],f[N][B];
inline void dfs(int u,int fa,cs int &bel){
	if(!tsiz[u])return ;
	group[u]=bel;
	Linear_base::copy(f[u],f[fa]);
	Linear_base::insert(f[u],g[u]);
	for(int re e=0;e<edge[u].size();++e){
		if(ban[edge[u][e]])continue;
		if(edge[u][e]^fa)dfs(edge[u][e],u,bel);
	}
}

inline void dfs_q(int u,int fa){
	if(last[u])tsiz[u]=1;
	else tsiz[u]=0;
	for(int re e=0;e<edge[u].size();++e)
	if(!ban[edge[u][e]]&&(edge[u][e]^fa))dfs_q(edge[u][e],u),tsiz[u]+=tsiz[edge[u][e]];
}

inline void calc(){
	ban[G]=true;
	group[G]=G;
	Linear_base::clear(f[G]);
	Linear_base::insert(f[G],g[G]);
	dfs_q(G,0);
	for(int re e=0;e<edge[G].size();++e)
	if(!ban[edge[G][e]])dfs(edge[G][e],G,edge[G][e]);
	for(int re i=1;i<=tail;++i){
		int re u=que[i];
		for(int re q=last[u],v=to[q];q;v=to[q=nxt[q]]){
			if(!have[q>>1]&&group[u]!=group[v]){
				have[q>>1]=true;
				Linear_base::merge(res,f[u],f[v]);
				ans[q>>1]=Linear_base::query(res);
			}
			while(nxt[q]&&have[nxt[q]>>1])nxt[q]=nxt[nxt[q]];
		}
	}
}

inline void dfs_banall(int u){
	ban[u]=true;
	for(int re e=0;e<edge[u].size();++e)
	if(!ban[edge[u][e]])dfs_banall(edge[u][e]);
}

signed main(){
	n=getint();
	q=getint();
	for(int re i=1;i<=n;++i)g[i]=getint();
	for(int re i=1;i<n;++i)addedge(getint(),getint());
	for(int re i=1;i<=q;++i)addq(getint(),getint());
	siz[1]=n;
	for(int re i=1;i<=n;++i){
		while(!ban[i]){
			tail=0;
			total=mx=siz[i];
			G=i;
			find_G(i,0);
			if(tail==0)dfs_banall(G);
			else calc();
		}
	}
	for(int re i=1;i<=q;++i)outint(ans[i]),pc('\n');
	FLUSH();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/85568253