卧薪尝胆,厚积薄发。
SCOI2016 幸运数字
Date: Fri Aug 10 22:25:42 CST 2018 In Category: NoCategory

Description:

给一棵树,每个点有权,给出一些路径,问在路径上选出一些点的异或最大值。
$n\le 20000$ $m \le 200000$

Solution:

异或最大值维护线性基,树上的路径问题还是离线无修改多组询问可以点分治,先把点分树建出来,然后把每个询问放在点分树 $LCA$ 上,求 $LCA$ 可以在点分树上暴力标记一个点的祖先,另一个点再暴力跳,由于点分树深度 $logn$ ,所以能保证复杂度。然后就可以点分治了,到每个点时求出来这个点到子树所有点的线性基, $dfs$ 时插入即可,然后枚举当前点的所有询问,合并两个线性基就可以求异或最大值了。
复杂度 $O(nlog^2n)$

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
int n,m;
#define MAXN 20010
typedef long long ll;
ll val[MAXN];
struct edge
{
int to,nxt;
}e[MAXN << 1];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b)
{
++edgenum;e[edgenum].to = b;e[edgenum].nxt = lin[a];lin[a] = edgenum;
++edgenum;e[edgenum].to = a;e[edgenum].nxt = lin[b];lin[b] = edgenum;
return;
}
#define MAXQ 200010
struct query
{
int a,b,nxt;
ll ans;
}q[MAXQ];
int querynum = 0;
int head[MAXN] = {0};
void addq(int a,int b,int lca)
{
++querynum;q[querynum].a = a;q[querynum].b = b;q[querynum].nxt = head[lca];head[lca] = querynum;
return;
}
#define MAXB 61
struct linear_base
{
ll d[MAXB];
linear_base(){memset(d,0,sizeof(d));}
void clear(){memset(d,0,sizeof(d));}
void insert(ll x)
{
for(int i = 60;i >= 0;--i)
{
if(x & (1ll << i))
{
if(d[i] == 0)
{
d[i] = x;
break;
}
else x ^= d[i];
}
}
return;
}
ll query()
{
ll res = 0;
for(int i = 60;i >= 0;--i)
{
if((res ^ d[i]) > res)
{
res ^= d[i];
}
}
return res;
}
}b[MAXN];
linear_base merge(linear_base a,linear_base b)
{
linear_base res = a;
for(int i = 0;i <= 60;++i)
{
if(b.d[i] != 0)
res.insert(b.d[i]);
}
return res;
}
int s,root;
int size[MAXN],d[MAXN];
bool v[MAXN];
void getroot(int k,int f)
{
size[k] = 1;d[k] = 0;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(v[e[i].to] || e[i].to == f)continue;
getroot(e[i].to,k);
size[k] += size[e[i].to];
if(size[e[i].to] > d[k])
{
d[k] = size[e[i].to];
}
}
d[k] = max(d[k],s - d[k]);
if(d[k] < d[root])root = k;
return;
}
void getbase(int k,int f,linear_base res)
{
res.insert(val[k]);
b[k] = res;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(v[e[i].to] || e[i].to == f)continue;
getbase(e[i].to,k,res);
}
return;
}
void calc(int k)
{
linear_base res;
getbase(k,0,res);
linear_base ans;
for(int i = head[k];i != 0;i = q[i].nxt)
{
ans = merge(b[q[i].a],b[q[i].b]);
q[i].ans = ans.query();
}
return;
}
int fa[MAXN];
vector<int> g[MAXN];
void divide(int k)
{
v[k] = true;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(v[e[i].to])continue;
root = 0;s = size[e[i].to];
getroot(e[i].to,k);
fa[root] = k;g[k].push_back(root);
divide(root);
}
return;
}
bool vis[MAXN];
int LCA(int a,int b)
{
vis[a] = true;
for(int i = a;fa[i] != 0;i = fa[i])vis[fa[i]] = true;
int ans;
if(vis[b])ans = b;
else for(int i = b;fa[i] != 0;i = fa[i])if(vis[fa[i]]){ans = fa[i];break;}
vis[a] = false;
for(int i = a;fa[i] != 0;i = fa[i])vis[fa[i]] = false;
return ans;
}
void work(int k)
{
v[k] = true;
calc(k);
for(int i = 0;i < g[k].size();++i)
{
work(g[k][i]);
}
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i)scanf("%lld",&val[i]);
int a,b;
for(int i = 1;i < n;++i)
{
scanf("%d%d",&a,&b);
add(a,b);
}
int rt;root = 0;d[0] = INF;s = n;
getroot(1,0);rt = root;
divide(root);
for(int i = 1;i <= m;++i)
{
scanf("%d%d",&a,&b);
addq(a,b,LCA(a,b));
}
memset(v,false,sizeof(v));
work(rt);
for(int i = 1;i <= m;++i)printf("%lld\n",q[i].ans);
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡