您的位置:首页 > 其它

[线性基 树链剖分 线段树 || ST表 || 点分治] BZOJ 4568 [Scoi2016]幸运数字

2017-07-01 22:06 525 查看
这个东西链剖之后就是个裸的区间线性基,是可以暴力合并的O(log2n)

所以暴力线段树是 O(nlog4n)

改成ST表是 O(nlog3n)

而如果点分的话 应该是O(nlog2n)

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;

inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
inline void read(ll &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=20005;
const int K=61;
const int KK=17;

ll tmp
,pnt;

struct Base{
int base[K]; ll b[K];
Base(){ }
Base(ll x){
*b=0; b[++*b]=x; for (int k=K-1;~k;k--) if (x>>k&1) { base[k]=1; break; }
}
void clear(){
cl(base); *b=0;
}
void Merge(ll *x,ll *y){
pnt=0;
for (int i=1;i<=*x;i++) tmp[++pnt]=x[i];
for (int i=1;i<=*y;i++) tmp[++pnt]=y[i];
cl(base); *b=0;
for (int i=1;i<=pnt;i++){
ll x=tmp[i];
for (int k=K-1;~k;k--)
if (x>>k&1)
if (!base[k]){
b[++*b]=x; base[k]=*b;
//for (int j=1;j<*b;j++)
//  if (b[j]>>k&1)
//  b[j]^=x;
break;
}else
x^=b[base[k]];
}
}
ll Query(){
ll x=0;
for (int k=K-1;~k;k--)
if (base[k] && (x^b[base[k]])>x)
x^=b[base[k]];
return x;
}
}st
[KK];

struct edge{
int u,v,next;
}G[N<<1];
int head
,inum;
inline void add(int u,int v,int p){
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
#define V G[p].v

int n;
ll val
;

int size
,fat
;
int depth
;

inline void dfs(int u,int fa){
size[u]=1; fat[u]=fa; depth[u]=depth[fa]+1;
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
dfs(V,u),size[u]+=size[V];
}

int pre
,clk,top
,back
;
inline void find(int u,int fa,int z){
pre[u]=++clk; top[u]=z; back[clk]=u;
int maxv=0,son=0;
for (int p=head[u];p;p=G[p].next)
if (V!=fa && size[V]>maxv)
maxv=size[son=V];
if (son) find(son,u,z);
for (int p=head[u];p;p=G[p].next)
if (V!=fa && V!=son)
find(V,u,V);
}

int Log
;
inline void Build(){
for (int i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
for (int i=1;i<=n;i++) st[i][0]=Base(val[back[i]]);
for (int k=1;k<KK;k++)
for (int i=1;i<=n;i++)
st[i][k].Merge(st[i][k-1].b,st[min(i+(1<<(k-1)),n+1)][k-1].b);
}

Base Ret;

inline void merge(int l,int r){
int t=Log[r-l+1];
Ret.Merge(Ret.b,st[l][t].b);
Ret.Merge(Ret.b,st[r-(1<<t)+1][t].b);
}

inline ll Query(int u,int v){
Ret.clear();
for (;top[u]!=top[v];u=fat[top[u]]){
if (depth[top[u]]<depth[top[v]]) swap(u,v);
merge(pre[top[u]],pre[u]);
}
if (depth[u]>depth[v]) swap(u,v);
merge(pre[u],pre[v]);
return Ret.Query();
}

int main(){
int x,y,Q;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); read(Q);
for (int i=1;i<=n;i++) read(val[i]);
for (int i=1;i<n;i++) read(x),read(y),add(x,y,++inum),add(y,x,++inum);
dfs(1,0); find(1,0,1); Build();
while (Q--){
read(x); read(y);
printf("%lld\n",Query(x,y));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: