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]);
}
对于作者转载文章,欢迎继续转载。
对于作者原创文章,请注明出处之后转载。