HDU5390 tree

传送门

题目大意

给定一棵 n 个节点的带点权树,进行 m 次操作,每次操作属于以下两类:

  1. 修改一个节点的权值.
  2. 对给定的节点 u ,求在 u 1 的路径上取节点 v ,能得到的 valuvalv 的最大值.

1n,m105,0vali109.

题解

看题解时学会了一种新的流算法叫做一眼流

首先询问的东西有关一个节点到根节点的路径,很自然会想到转化为修改时更新一棵子树的信息,于是用dfs+线段树.
找异或的最大值也自然会往Trie树上靠.
所以比较裸的做法是线段树套Trie树,要注意的是区间更新打标记的问题.可以只在线段树的这个节点的Trie树上进行删除和插入操作,然后单点询问时对线段树路径上的每个节点的Trie树都贪心地求解一次取最大值即可.

也就是说,线段树上的延迟更新标记是根本不用下传的.

分析一下这样做的时空复杂度,设点权的二进制位数为 S (大概是 30 ),时间复杂度显然是 O(Snlgn) ,因为每次会更新到 O(lgn) 棵Trie树,所以空间复杂度也是 O(Snlgn) ,加上一点常数内存就被卡掉了 :P

然后有一种比较奥妙也比较少见的做法,在线段树上离线做.

其实也没那么玄乎,上面已经说过标记不用下传,那么线段树上每个节点实际上都是独立的,所以对每个节点,把有关的各种删除,插入和更新答案的操作按顺序做一遍就行了.这样做不会影响时间复杂度.
因为只需要维护每个节点的一棵Trie树,而与其有关的删除,插入操作个数是 O(n) 的,所以空间复杂度优化到了 O(Sn) .

代码

#include
#include
#include
using namespace std;
const int N=(int)1e5+5,LEN=31;
int n,tot_edge,dfs_clock,head[N],val[N],pre[N],post[N],ans[N];
struct Edge{
    int to,nxt;
    Edge(){}
    Edge(int to,int nxt):to(to),nxt(nxt){}
}edge[N<<1];
struct Ope{
    bool type;
    int num,aux;
    /*
        type=0:update
            aux:-1 or 1

        type=1:query
            aux:id of the query
    */
    Ope(){}
    Ope(bool type,int num,int aux):type(type),num(num),aux(aux){}
};
struct Trie{
    static const int NODE=LEN*N<<1;
    int allc,son[NODE][2],mul[NODE];
    bool bin[LEN];
    inline void init(){
        son[0][0]=son[0][1]=allc=0;
    }
    void convert(int num){
        for(int i=LEN-1;~i;--i,num>>=1)
            bin[i]=num&1;
    }
    int newNode(){
        ++allc;
        mul[allc]=son[allc][0]=son[allc][1]=0;
        return allc;
    }
    void update(int num,int sgn){
        convert(num);
        for(int i=0,cur=0;iif(!son[cur][bin[i]])
                son[cur][bin[i]]=newNode();
        }
    }
    int query_mx(int num){
        convert(num);
        int res=0;
        for(int i=0,cur=0;i1;
            if(mul[son[cur][bin[i]^1]]){
                res|=1;
                cur=son[cur][bin[i]^1];
            }
            else cur=son[cur][bin[i]];
        }
        return res;
    }
}trie;
struct Segment_Tree{
    vectorope[N<<2];
    #define lson l,mid,k<<1
    #define rson mid+1,r,k<<1|1
    void build(int l=1,int r=n,int k=1){
        ope[k].clear();
        if(l==r)return;
        int mid=l+r>>1;
        build(lson);
        build(rson);
    }
    void update(int L,int R,int num,int sgn,int l=1,int r=n,int k=1){
        if(l==L&&r==R){
            ope[k].push_back(Ope(0,num,sgn));
            return;
        }
        int mid=l+r>>1;
        if(R<=mid)update(L,R,num,sgn,lson);
        else if(L>mid)update(L,R,num,sgn,rson);
        else{
            update(L,mid,num,sgn,lson);
            update(mid+1,R,num,sgn,rson);
        }
    }
    void query(int tar,int num,int id,int l=1,int r=n,int k=1){
        ope[k].push_back(Ope(1,num,id));
        if(l==r)return;
        int mid=l+r>>1;
        if(tar<=mid)query(tar,num,id,lson);
        else query(tar,num,id,rson);
    }
    inline void Max(int &a,int b){
        if(b>a)a=b;
    }
    void consider(int l=1,int r=n,int k=1){
        trie.init();
        for(int i=0;i<(int)ope[k].size();++i){
            int num=ope[k][i].num,
                aux=ope[k][i].aux;
            if(ope[k][i].type){
                Max(ans[aux],trie.query_mx(num));
            }
            else{
                trie.update(num,aux);
            }
        }
        if(l==r)return;
        int mid=l+r>>1;
        consider(lson);
        consider(rson);
    }
}sgt;
inline void rd(int &res){
    res=0;
    char c;
    while(c=getchar(),c<48);
    do res=(res<<3)+(res<<1)+(c^48);
        while(c=getchar(),c>47);
}
void add_edge(int u,int v){
    edge[tot_edge]=Edge(v,head[u]);
    head[u]=tot_edge++;
}
void dfs(int cur,int par=0){
    pre[cur]=++dfs_clock;
    for(int i=head[cur];~i;i=edge[i].nxt){
        int son=edge[i].to;
        if(son==par)continue;
        dfs(son,cur);
    }
    post[cur]=dfs_clock;
}
void solve(){
    int m;
    rd(n);rd(m);
    tot_edge=0;
    memset(head,-1,n+1<<2);
    for(int i=2,par;i<=n;++i){
        rd(par);
        add_edge(i,par);
        add_edge(par,i);
    }
    for(int i=1;i<=n;++i)
        rd(val[i]);
    dfs_clock=0;
    dfs(1);
    sgt.build();
    for(int i=1;i<=n;++i)
        sgt.update(pre[i],post[i],val[i],1);
    int cnt_query=0;
    for(int i=0,ope,u;iif(ope){
            sgt.query(pre[u],val[u],cnt_query);
            ans[cnt_query++]=0;
        }
        else{
            sgt.update(pre[u],post[u],val[u],-1);
            rd(val[u]);
            sgt.update(pre[u],post[u],val[u],1);
        }
    }
    sgt.consider();
    for(int i=0;iprintf("%d\n",ans[i]);
}
int main(){
    int cas;
    rd(cas);
    while(cas--)solve();
    return 0;
}
/*

    Jul.06.16

    Tags:dfs,segment tree,trie
    Submissions:1

    Memory(KB) 118200
    Time(ms) 2730
    Length(Bytes) 3372

*/

你可能感兴趣的:(题目解读,HDU,图论,---树,----,---dfs序,数据结构,---线段树,---Trie树,离线)