bzoj 4568: [Scoi2016]幸运数字

ST表维护线性基,用ST表维护不带修改的东西可以比树剖少一个log。注意维护线性基是60*60的复杂度。
   
   
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
 
#define ll long long
#define inf 1e9
#define eps 1e-8
#define md
#define N 20010
using namespace std;
struct yts { int x,t,ne;} e[2*N];
int fa[N][15],v[N],dep[N];
ll c[N][15][60],Ans[60];
int n,num;
 
void put(int x,int y)
{
num++; e[num].x=x; e[num].t=y;
e[num].ne=v[x]; v[x]=num;
}
 
void dfs(int x)
{
for (int i=v[x];i;i=e[i].ne)
{
int y=e[i].t;
if (y!=fa[x][0])
{
dep[y]=dep[x]+1; fa[y][0]=x;
dfs(y);
}
}
}
 
void merge(ll *ans,ll *a)
{
for (int i=59;i>=0;i--)
if (a[i])
{
ll x=a[i];
for (int j=59;j>=0;j--)
if (x&(1ll<<j))
{
if (ans[j]) x^=ans[j];
else { ans[j]=x; break;}
}
}
}
 
void build_lca()
{
for (int j=1;j<15;j++)
for (int i=1;i<=n;i++)
if (fa[i][j-1])
{
fa[i][j]=fa[fa[i][j-1]][j-1];
memcpy(c[i][j],c[i][j-1],sizeof(c[i][j-1]));
merge(c[i][j],c[fa[i][j-1]][j-1]);
}
}
int get(int x,int y)
{
memset(Ans,0,sizeof(Ans));
if (dep[x]<dep[y]) swap(x,y);
int t=dep[x]-dep[y];
for (int j=14;j>=0;j--)
if (t&(1<<j))
{
merge(Ans,c[x][j]);
x=fa[x][j];
}
if (x==y) return x;
for (int j=14;j>=0;j--)
if (fa[x][j]!=fa[y][j])
{
merge(Ans,c[x][j]); merge(Ans,c[y][j]);
x=fa[x][j]; y=fa[y][j];
}
merge(Ans,c[x][0]); merge(Ans,c[y][0]);
return fa[x][0];
}
int main()
{
int Q;
scanf("%d%d",&n,&Q);
for (int i=1;i<=n;i++)
{
ll x;
scanf("%lld",&x);
Ans[0]=x; merge(c[i][0],Ans);
}
for (int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
put(x,y); put(y,x);
}
dep[1]=1; dfs(1); build_lca();
for (int i=1;i<=Q;i++)
{
int x,y;
scanf("%d%d",&x,&y);
int z=get(x,y);
merge(Ans,c[z][0]);
ll ans=0;
for (int j=59;j>=0;j--)
ans=max(ans,ans^Ans[j]);
printf("%lld\n",ans);
}
return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值