Codeforces1778E 【线性基】【换根DP】
我,差30秒,就能AC这道题,我知道错哪的时候是倒计时30,不记得优先级想赌一把,因为我没有先写括号的习惯,所以倒计时14的时候交了,然后想改了括号再交一发,改了括号之后,比赛结束了。
这题很简单,就是你任意选一个点作为根节点,然后你会发现,它给你的\(r\)如果在\(v\)的子树中,其实就相当于砍掉\(v\)对应的那部分子树,我们可以想到一个线性基合并的做法。首先求出子树的线性基,如果\(r\)不在\(v\)的子树中,那么子树的线性基最大值就是答案。否则我们可以找出\(r\)对应的\(v\)的那个儿子。我们用一个线性基记录它父亲砍掉它得到的线性基,然后对它的儿子做一个线性基的前缀和以及线性基的后缀和。对于\(r\)在\(v\)子树中的情况,我们把对应儿子的前缀和和后缀和合并,就可以得到对应线性基的最大值。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 205000;
const int mod = 998244353;
int n,q;
int a[maxn];
vector<int> g[maxn];
int fa[maxn];
struct query{
int r,v,ans,flag;
}qy[maxn];
vector<pair<int,int> > pg[maxn];
vector<int> qg[maxn];
int son[maxn];
struct xxg{
int a[30];
}xr[maxn],xp[maxn],xz[maxn];
xxg merge(xxg alpha,xxg beta){
for(int i=29;i>=0;i--){
if(alpha.a[i]){
for(int j=i;j>=0;j--){
if((alpha.a[i]&(1<<j)) == 0) continue;
if(!beta.a[j]) {beta.a[j] = alpha.a[i];break;}
else alpha.a[i] ^= beta.a[j];
}
}
}
return beta;
}
void dfs(int now,int pa){
fa[now] = pa; son[now] = 0;
for(auto x:pg[now]){
if(son[x.first]){
qy[x.second].r = son[x.first];
qy[x.second].flag = 1;
}
}
for(int i=0;i<g[now].size();i++){
if(g[now][i] == pa){
swap(g[now][i],g[now][g[now].size()-1]);
g[now].pop_back();
i--;continue;
}
son[now] = g[now][i];
dfs(g[now][i],now);
}
son[now] = 0;
}
void dfs2(int now){
for(int i=0;i<g[now].size();i++){
dfs2(g[now][i]);
xr[now] = merge(xr[now],xr[g[now][i]]);
}
int kk = a[now];
for(int j=29;j>=0;j--){
if(!(kk & (1<<j))) continue;
if(!xr[now].a[j]) {xr[now].a[j] = kk;break;}
else kk ^= xr[now].a[j];
}
kk = 0;
for(int j=29;j>=0;j--){
if(!(kk & (1<<j)))
kk ^= xr[now].a[j];
}
for(auto x:pg[now]){
qy[x.second].ans = kk;
}
}
void dfs3(int now,xxg xnow){
int kk = a[now];
for(int j=29;j>=0;j--){
if(!(kk & (1<<j))) continue;
if(!xnow.a[j]) {xnow.a[j] = kk;break;}
else kk ^= xnow.a[j];
}
xxg pri = xnow;
for(int i=0;i<g[now].size();i++){
xp[g[now][i]] = pri;
pri = merge(pri,xr[g[now][i]]);
}
pri = xnow;
for(int i=g[now].size()-1;i>=0;i--){
xz[g[now][i]] = pri;
pri = merge(pri,xr[g[now][i]]);
}
for(int i=0;i<g[now].size();i++){
pri = merge(xp[g[now][i]],xz[g[now][i]]);
kk = 0;
for(int j=29;j>=0;j--){
if(!(kk & (1<<j)))
kk ^= pri.a[j];
}
for(auto x:qg[g[now][i]]){
qy[x].ans = kk;
}
dfs3(g[now][i],pri);
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t; cin>>t;
while(t--){
cin >> n;
for(int i=1;i<=n;i++) fa[i] = 0,g[i].clear();
for(int i=1;i<=n;i++) pg[i].clear(),qg[i].clear();
for(int i=1;i<=n;i++) for(int j=29;j>=0;j--) xr[i].a[j]=xp[i].a[j]=xz[i].a[j]=0;
for(int i=1;i<=n;i++) cin >> a[i];
for(int i=1;i<n;i++){
int u,v; cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
cin >> q;
for(int i=1;i<=q;i++){
int r,v; cin >> r >> v;
if(r == v) r = v = 1;
qy[i] = (query){r,v,0,0};
pg[r].push_back(make_pair(v,i));
}
dfs(1,0);
for(int i=1;i<=n;i++) pg[i].clear();
for(int i=1;i<=q;i++){
if(qy[i].flag == 0) {qy[i].r = qy[i].v;
pg[qy[i].v].push_back(make_pair(qy[i].r,i));
}else{
qg[qy[i].r].push_back(i);
}
}
dfs2(1);
xxg emp;
memset(emp.a,0,sizeof(emp.a));
dfs3(1,emp);
for(int i=1;i<=q;i++){
cout<<qy[i].ans<<'\n';
}
}
}