zoukankan      html  css  js  c++  java
  • [TJOI2018]xor

    题目大意:

    有一棵树,根节点为1。每个点有点权。有两种操作。

    1. 求节点x所在子树中点权与y异或的最大值。
    2. 求x到y的路径上点权与z异或的最大值。

    解题思路:

    可持久化字典树。

    对于第一种操作,我们对树进行dfs遍历,求出每个节点的dfs序(树剖),然后由于子树中dfs序连续,所以相当于区间的询问。对每个1~x区间建trie即可。

    对于第二种操作,我们对每个节点建一颗trie,记录其到根的路径上的信息。

    然后常规求LCA,减一减即可。

    C++ Code:

    #include<bits/stdc++.h>
    const int N=1e5+5;
    int ch[N<<6][2],siz[N<<6],ccnt=0,n,q,a[N],head[N],to[N<<1],nxt[N<<1];
    int sz[N],dep[N],son[N],top[N],trie1[N],trie2[N],dfn[N],idfn[N],idx=0,fa[N],ans;
    inline int readint(){
        int c=getchar(),d=0;
        for(;!isdigit(c);c=getchar());
        for(;isdigit(c);c=getchar())
        d=(d<<3)+(d<<1)+(c^'0');
        return d;
    }
    void Insert(int&nw,int&o,int&p,int pp=30){
        nw=++ccnt;
        if(!~pp)return(void)(siz[nw]=siz[o]+1);
        ch[nw][0]=ch[o][0];
        ch[nw][1]=ch[o][1];
        int nxt=(p>>pp)&1;
        Insert(ch[nw][nxt],ch[o][nxt],p,pp-1);
        siz[nw]=siz[ch[nw][0]]+siz[ch[nw][1]];
    }
    void dfs1(int now,int pre){
        sz[now]=1;
        Insert(trie1[now],trie1[pre],a[now]);
        for(int i=head[now];i;i=nxt[i])
        if(!dep[to[i]]){
            dep[to[i]]=dep[now]+1;
            fa[to[i]]=now;
            dfs1(to[i],now);
            sz[now]+=sz[to[i]];
            if(!son[now]||sz[to[i]]>sz[son[now]])son[now]=to[i];
        }
    }
    void dfs2(int now){
        idfn[dfn[now]=++idx]=now;
        if(son[now])top[son[now]]=top[now],dfs2(son[now]);
        for(int i=head[now];i;i=nxt[i])
        if(to[i]!=son[now]&&dep[to[i]]>dep[now])
        dfs2(top[to[i]]=to[i]);
    }
    inline int LCA(int x,int y){
        while(top[x]!=top[y])
        if(dep[top[x]]>=dep[top[y]])x=fa[top[x]];else
        y=fa[top[y]];
        return dep[x]<dep[y]?x:y;
    }
    void query(int&R,int&L,int&num,int pp=30){
        if(!~pp)return;
        int nw=(num>>pp)&1^1;
        if(siz[ch[R][nw]]>siz[ch[L][nw]]){
            ans|=1<<pp;
            query(ch[R][nw],ch[L][nw],num,pp-1);
        }else
        query(ch[R][!nw],ch[L][!nw],num,pp-1);
    }
    void query2(int&x,int&y,int&lca,int&fa,int&num,int pp=30){
        if(!~pp)return;
        int nw=(num>>pp)&1^1;
        if(siz[ch[x][nw]]+siz[ch[y][nw]]-siz[ch[lca][nw]]-siz[ch[fa][nw]]>0){
            ans|=1<<pp;
            query2(ch[x][nw],ch[y][nw],ch[lca][nw],ch[fa][nw],num,pp-1);
        }else
        query2(ch[x][!nw],ch[y][!nw],ch[lca][!nw],ch[fa][!nw],num,pp-1);
    }
    int main(){
        n=readint(),q=readint();
        for(int i=1;i<=n;++i)a[i]=readint();
        for(int i=1;i<n;++i){
            int u=readint(),v=readint();
            to[i<<1]=v;nxt[i<<1]=head[u];
            head[u]=i<<1;
            to[i<<1|1]=u;nxt[i<<1|1]=head[v];
            head[v]=i<<1|1;
        }
        memset(dep,0,sizeof dep);
        memset(son,0,sizeof son);
        dep[1]=1;
        dfs1(1,0);
        dfs2(1);
        for(int i=1;i<=n;++i)
        Insert(trie2[i],trie2[i-1],a[idfn[i]]);
        while(q--)
        if(readint()==1){
            int x=readint(),y=readint();
            ans=0;query(trie2[dfn[x]+sz[x]-1],trie2[dfn[x]-1],y);
            printf("%d
    ",ans);
        }else{
            int x=readint(),y=readint(),z=readint();
            int lca=LCA(x,y);
            ans=0;
            query2(trie1[x],trie1[y],trie1[lca],trie1[fa[lca]],z);
            printf("%d
    ",ans);
        }
        return 0;
    }
    

      

  • 相关阅读:
    jquery筛选数组之grep、each、inArray、map的用法及遍历json对象 [转]
    fontface 自定义字体
    (转)闭包与柯里化
    简单的等级评分效果
    js对象字面量
    利用jqueryRotare实现抽奖转盘
    [转]移动终端开发必备知识
    jQuery ajax中使用serialize() 方法提交表单数据
    css3动画模块transform transition animation属性解释
    【备忘】canvas下图片翻转转自oldj.net(英杰兄)
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/9605160.html
Copyright © 2011-2022 走看看