1. 程式人生 > 實用技巧 >luoguP6018 [Ynoi2010]Fusion tree 01trie

luoguP6018 [Ynoi2010]Fusion tree 01trie

今年省選考了這個技巧,感覺之前沒做過類似的題的話現場挺難想出來的.

我們發現對 1 個數 +1 可以看作從低到高位的第一個 0 修改成 1,該 0 後面的 1 修改成 0.

將一個節點的所有兒子對應的數放到該節點對應的 01 trie 中進行修改的話就是將 0,1 翻轉.

翻轉後走 0 那邊,然後遞迴地進行翻轉就行.

然後注意在插入地時候即使 v=0 也要一直遞迴下去,因為我們是從低位向高位進行插入.

code:

#include <cstdio>  
#include <algorithm> 
#include <cstring>        
#define MA 20  
#define N 1000009
#define ll long long
#define lson s[x].ch[0]
#define rson s[x].ch[1]
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;       
int n,m,edges,tot; 
int hd[N],to[N<<1],nex[N<<1],fa[N],rt[N],a[N],addv[N];         
struct data {  
    int si,sum,cur,ch[2];  
}s[N*30];     
void pushup(int x) {             
    s[x].sum=s[lson].sum^s[rson].sum;       
    if(s[rson].si&1) s[x].sum+=1<<s[rson].cur;             
}
void ins(int x,int v,int cur) {  
    if(cur>20) return;  
    if(v&1) {  
        if(!rson) {
            rson=++tot;            
            s[rson].cur=cur;         
        }        
        ++s[rson].si;  
        ins(rson,v>>1,cur+1);                          
    }  
    else {                    
        if(!lson) {          
            lson=++tot; 
            s[lson].cur=cur; 
        }         
        ++s[lson].si; 
        ins(lson,v>>1,cur+1); 
    }  
    pushup(x); 
}          
void del(int x,int v,int cur=0) {  
    if(cur>20) return;  
    if(v&1) { 
        --s[rson].si; 
        del(rson,v>>1,cur+1); 
    } 
    else {     
        --s[lson].si; 
        del(lson,v>>1,cur+1); 
    }  
    pushup(x);   
}    
void upd(int x) {  
    if(!x) return;         
    swap(lson,rson),upd(lson),pushup(x);           
} 
void add(int u,int v) { 
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; 
}  
void dfs(int x,int ff) {   
    fa[x]=ff; 
    for(int i=hd[x];i;i=nex[i]) if(to[i]!=ff) dfs(to[i],x); 
}       
char *p1,*p2,buf[100000];  
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)   
int rd() {  
    char c;  int x=0; 
    do { c=nc(); } while(c<48);    
    while(c>47) { 
        x=(((x<<2)+x)<<1)+(c^48),c=nc(); 
    }  
    return x;  
}
int main() {  
    // setIO("input");     
    // freopen("input.out","w",stdout); 
    int x,y,z;  
    n=rd(),m=rd();  
    for(int i=1;i<n;++i) {  
        x=rd(),y=rd();  
        add(x,y),add(y,x); 
    }     
    for(int i=1;i<=n;++i) a[i]=rd();   
    dfs(1,0); 
    for(int i=1;i<=n;++i) {                    
        rt[i]=++tot; 
        for(int j=hd[i];j;j=nex[j]) {   
            y=to[j]; 
            if(y==fa[i]) continue;   
            ins(rt[i],a[y],0);      
        }  
    } 
    int op; 
    for(int i=1;i<=m;++i) { 
        op=rd(); 
        if(op==1) { 
            x=rd();  
            upd(rt[x]);        
            if(fa[x]) { 
                z=fa[fa[x]];  
                if(z) {                      
                    del(rt[z],a[fa[x]]+addv[z]); 
                    ins(rt[z],a[fa[x]]+addv[z]+1,0);    
                }        
                ++a[fa[x]];    
            }             
            ++addv[x];    
        }
        if(op==2) {       
            x=rd(),y=rd();  
            if(fa[x]) { 
                del(rt[fa[x]],a[x]+addv[fa[x]]);        
                ins(rt[fa[x]],a[x]+addv[fa[x]]-y,0);  
            }  
            a[x]-=y;  
        }
        if(op==3) {             
            x=rd();           
            printf("%d\n",s[rt[x]].sum^(a[fa[x]]+addv[fa[fa[x]]]));    
        }       
    }    
    return 0; 
}