HDU 5390 tree

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

给出一棵n(10w)的有根树。共m(10w)个操作:
0 u v - au=v (ai109)
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
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值