给出一棵n(≤10w)的有根树。共m(≤10w)个操作:
0 u v - au=v (ai≤109)
1 u 询问点u到根的路径上的点与u点权异或和的最大值
Trie+分治+线段树
PS:也许将空间复杂度降至O(nw)的分治很惊艳,然而最让我耳目一新的是标记不下传的线段树。
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<cstdio>
#include<bitset>
#include<cassert>
#include<cstring>
#include<complex>
#include<iostream>
#include<algorithm>
#define pi acos(-1)
#define inf (1<<30)
#define INF (1<<62)
#define y1 bflaisfnmasf
#define y2 fsafgmalg
#define tm afnsjkf
#define j1 sfakf
#define j2 fasndfkas
#define fi first
#define se second
#define CLR(x,f) memset(x,f,sizeof(x))
#define CPY(x,y) memcpy(x,y,sizeof(x))
#define prt(x) cout<<#x<<":"<<x<<" "
#define prtn(x) cout<<#x<<":"<<x<<endl
#define huh(x) printf("--------case(%d)--------\n",x)
#define travel(x) for(Edge *e=h[x];e;e=e->n)
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
typedef pair<int,ii> iii;
const int M=100005;
int last[M],ecnt,n,m;
struct Edge{
int to,nxt;
Edge(){}
Edge(int to_,int nxt_):to(to_),nxt(nxt_){}
}edge[M];
void ins(int u,int v){
edge[ecnt]=Edge(v,last[u]);last[u]=ecnt++;
}
int lx[M],rx[M],dfs_clock;
void dfs(int x){
lx[x]=++dfs_clock;
for(int i=last[x];i!=-1;i=edge[i].nxt)
dfs(edge[i].to);
rx[x]=dfs_clock;
}
struct node{
int id,val,det;
node(){}
node(int id_,int val_,int det_):id(id_),val(val_),det(det_){}
};
struct Trie{
static const int N=M*25;
int root,tot;
int c[N][2],sz[N];//
int q[32];
int newnode(){
++tot;
c[tot][0]=c[tot][1]=sz[tot]=0;
return tot;
}
void init(){
tot=0;
root=newnode();
}
void update(int x,int f){
for(int i=0;i<31;i++,x>>=1)q[30-i]=x&1;
int pre=root;
sz[pre]+=f;
for(int i=0;i<31;i++){
if(!c[pre][q[i]])c[pre][q[i]]=newnode();
pre=c[pre][q[i]];
sz[pre]+=f;
}
}
int calc(int x){
if(!sz[root])return 0;
for(int i=0;i<31;i++,x>>=1)q[30-i]=x&1;
int ans=0,pre=root;
for(int i=0;i<31;i++){
if(c[pre][q[i]^1]&&sz[c[pre][q[i]^1]]){
pre=c[pre][q[i]^1];
ans|=1<<30-i;
}
else pre=c[pre][q[i]];
}
return ans;
}
}trie;
int ans[M];
struct Segment{
vector<node>v[M<<2];
void build(int x,int l,int r){
v[x].clear();
if(l==r)return;
int mid=l+r>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
}
void update(int x,int l,int r,int L,int R,node t){
if(L<=l&&r<=R){
v[x].push_back(t);
return;
}
int mid=l+r>>1;
if(L<=mid)update(x<<1,l,mid,L,R,t);
if(R>mid)update(x<<1|1,mid+1,r,L,R,t);
}
void query(int x,int l,int r,int to,node t){
v[x].push_back(t);
if(l==r)return;
int mid=l+r>>1;
if(to<=mid)query(x<<1,l,mid,to,t);
else query(x<<1|1,mid+1,r,to,t);
}
void solve(int x,int l,int r){
if(v[x].size()){
trie.init();
node t;
for(int i=0;i<v[x].size();i++){
t=v[x][i];
if(t.id){
ans[t.id]=max(ans[t.id],trie.calc(t.val));
/*query*/
}
else{
trie.update(t.val,t.det);
/*update*/
}
}
}
if(l==r)return;
int mid=l+r>>1;
solve(x<<1,l,mid);
solve(x<<1|1,mid+1,r);
}
}sgm;
int num[M];
void solve(){
scanf("%d%d",&n,&m);
memset(last,-1,n+1<<2);
ecnt=dfs_clock=0;
for(int f,i=2;i<=n;i++){
scanf("%d",&f);
ins(f,i);
}
dfs(1);
sgm.build(1,1,n);
node t;
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
t=node(0,num[i],1);
sgm.update(1,1,n,lx[i],rx[i],t);
}
for(int u,v,w,i=1;i<=m;i++){
scanf("%d%d",&u,&v);
node t;
if(u==0){
scanf("%d",&w);
t=node(0,num[v],-1);
sgm.update(1,1,n,lx[v],rx[v],t);
num[v]=w;
t=node(0,num[v],1);
sgm.update(1,1,n,lx[v],rx[v],t);
ans[i]=-1;//没必要回答
}
else{
t=node(i,num[v],0);
sgm.query(1,1,n,lx[v],t);
//* sgm.update(1,1,n,v,rx[v],t);
ans[i]=0;
}
}
sgm.solve(1,1,n);
for(int i=1;i<=m;i++)
if(ans[i]!=-1)printf("%d\n",ans[i]);
}
int main(){
int cas;scanf("%d",&cas);
while(cas--)solve();
return 0;
}
/*
only query
1
10 1
1 1 2 2 3 1 2 3 5
23512 460943 835901 491571 399045 488033 187367 800843 734984 106134
1 6
ans=766812
*/

本文介绍了一种解决有根树上特定操作和查询问题的方法,包括使用Trie树进行快速查找最大异或值,结合分治策略降低空间复杂度,并运用线段树实现高效更新与查询。该算法涉及复杂的树形数据结构和高效的查询技术。
282

被折叠的 条评论
为什么被折叠?



