[2021.1.26多校省选模拟9]松鼠串门
询问树上一些父子链的最大异或和.N<=5e5
首先可以想到一个
O
(
n
l
o
g
n
w
2
)
O(nlognw^2)
O(nlognw2)的做法,就是倍增维护线性基,每次线性基合并是
O
(
w
2
)
O(w^2)
O(w2)
然后对于这种父子链我们考虑让儿子继承父亲信息.然后离线询问,采取类似于区间上的离线策略,统计每一个左端点的答案,然后每次移动右端点,这样我们就能够将一些问题贪心处理,让对应贡献在最靠右的位置产生。
但是关键在于深度限制,这里有一个关键思想,就是实际上对于线性基有效的信息并不多,所以我们对于每个基可以贪心地让它的对应深度尽量大,然后我们需要将插入过程进行修改,同时保证对应基的深度尽量大。
#include<bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define V inline void
#define I inline int
#define FOR(i,a,b) for(register int i=a,end##i=b;i<=end##i;++i)
#define REP(i,a,b) for(register int i=a,end##i=b;i>=end##i;--i)
using namespace std;
inline ULL read()
{
char x='\0';
ULL fh=1,sum=0;
for(x=getchar();x<'0'||x>'9';x=getchar())if(x=='-')fh=-1;
for(;x>='0'&&x<='9';x=getchar())sum=sum*10+x-'0';
return fh*sum;
}
const int N=1e6+9;
int n,m;
struct liner{
ULL base[69];
int dep[69];
liner(){FOR(i,0,64)base[i]=dep[i]=0;}
V insert(ULL val,int depth)
{
REP(i,64,1)
{
if((val>>(i-1))&1)
{
if(base[i]==0)
{
base[i]=val;
dep[i]=depth;
break;
}
else if(depth>dep[i])
{
ULL tmp=val;
val^=base[i];
base[i]=tmp;
swap(dep[i],depth);
}
else val^=base[i];
}
}
}
ULL que(int depth)
{
ULL ans=0;
REP(i,64,1)if(dep[i]>=depth&&(ans^base[i])>ans)ans^=base[i];
return ans;
}
};
struct lian{
int to,pre;
}e[N<<1];
int hed[N],lcnt=1;
V jlian(int x,int y)
{
e[++lcnt]={y,hed[x]};
hed[x]=lcnt;
}
int opt[N];
ULL ai[N];
vector<pair<int,int> >q[N];
ULL ans[N];
int dep[N];
V dfs(int x,int fa,liner now,int depth)
{
dep[x]=depth;
now.insert(ai[x],dep[x]);
for(auto t:q[x])
{
int id=t.second,dis=t.first;
ans[id]=now.que(dep[x]-dis);
}
for(int i=hed[x];i;i=e[i].pre)
{
int to=e[i].to;
if(to==fa)continue;
dfs(to,x,now,depth+1);
}
}
V file()
{
freopen("squirrel.in","r",stdin);
freopen("squirrel.out","w",stdout);
}
int main()
{
file();
n=read(),m=read();
// cout<<n<<' '<<m<<endl;//
FOR(i,1,n)
{
int fa=read();
ai[i]=read();
if(fa)jlian(fa,i),jlian(i,fa);
}
FOR(i,1,m)
{
opt[i]=read();
ULL u=read(),v=read();
if(opt[i]==0)q[u].push_back(make_pair(v,i));
else
{
ai[++n]=v;
jlian(u,n),jlian(n,u);
}
}
// cout<<"!"<<endl;//
dfs(1,0,liner(),1);
FOR(i,1,m)if(opt[i]==0)printf("%llu\n",ans[i]);
return 0;
}
/*
3 4
0 7
1 2
2 4
0 3 1
0 3 2
1 2 1
0 4 1
*/