P4592 [TJOI2018]异或 树链剖分 01trie

树剖上维护可持久化01trie即可

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<‘=‘<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
const int N=2e6+10;
int T[N],Siz[N<<5],t[N<<5][2],ncnt;
void upnode(int k,int val,int pre,int &pos)
{
    pos=++ncnt;
    Siz[pos]=Siz[pre]+1;
    t[pos][0]=t[pre][0];
    t[pos][1]=t[pre][1];
    if(k<0)return ;
    int c=(val>>k)&1;
    upnode(k-1,val,t[pre][c],t[pos][c]);
}
int qmax(int k,int val,int pre,int pos)
{
    if(k<0)return 0;
    int c=(val>>k)&1;
    int si=Siz[t[pos][c^1]]-Siz[t[pre][c^1]];
    if(si)return (1<<k)+qmax(k-1,val,t[pre][c^1],t[pos][c^1]);
    else return qmax(k-1,val,t[pre][c],t[pos][c]);
}
int head[N],top[N],pos,id[N],tot,fa[N],dep[N],son[N],siz[N],n,m,node[N];
struct Edge{int to,nex;}edge[N<<1];
void add(int a,int b){edge[++pos]=(Edge){b,head[a]};head[a]=pos;}

void dfs1(int x,int f)
{
    fa[x]=f;dep[x]=dep[f]+1;siz[x]=1;son[x]=0;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(v==f)continue;
        dfs1(v,x);siz[x]+=siz[v];
        if(siz[son[x]]<siz[v])son[x]=v;
    }
}
void dfs2(int x,int topf)
{
    top[x]=topf;id[x]=++tot;
    upnode(30,node[x],T[tot-1],T[tot]);
    if(son[x])dfs2(son[x],topf);
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;if(v==fa[x]||v==son[x])continue;
        dfs2(v,v);
    }
}
int Qmax(int x,int y,int val)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=max(ans,qmax(30,val,T[id[top[x]]-1],T[id[x]]));
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    ans=max(ans,qmax(30,val,T[id[x]-1],T[id[y]]));
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    rep(i,1,n)
    scanf("%d",&node[i]);
    rep(i,1,n-1)
    {
        int a,b;scanf("%d%d",&a,&b);
        add(a,b);add(b,a);
    }
    dfs1(1,0);
    dfs2(1,1);int x,y,z,op;
    while(m--)
    {
        scanf("%d",&op);
        if(op==1)scanf("%d%d",&x,&y),printf("%d\n",qmax(30,y,T[ id[x]-1 ],T[ id[x]+siz[x]-1 ] ));
        else scanf("%d%d%d",&x,&y,&z), printf("%d\n",Qmax(x,y,z));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/bxd123/p/11516702.html

时间: 2024-10-08 05:12:16

P4592 [TJOI2018]异或 树链剖分 01trie的相关文章

从lca到树链剖分 bestcoder round#45 1003

bestcoder round#45 1003 题,给定两个点,要我们求这两个点的树上路径所经过的点的权值是否出现过奇数次.如果是一般人,那么就是用lca求树上路径,然后判断是否出现过奇数次(用异或),高手就不这么做了,直接树链剖分.为什么不能用lca,因为如果有树退化成链,那么每次询问的复杂度是O(n), 那么q次询问的时间复杂度是O(qn) 什么是树链剖分呢? 就是把树的边分成轻链和重链 http://blogsina.com.cn/s/blog_6974c8b20100zc61.htmlh

【BZOJ-4568】幸运数字 树链剖分 + 线性基合并

4568: [Scoi2016]幸运数字 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 238  Solved: 113[Submit][Status][Discuss] Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市

BZOJ 2819 Nim 树链剖分

题目大意:两个小人在树上玩Nim游戏,问有没有必胜策略. 思路:尼姆游戏:如果所有石子的异或值为0就是必败局面.异或有如下性质:x ^ y ^ z = x ^ (y ^ z),所以就可以进行树链剖分了.题目中还好心提醒有30%的点会使dfs爆栈..第一次写不用dfs的树链剖分,扒的别人的代码,有些丑陋. CODE: #include <queue> #include <cstdio> #include <cstring> #include <iostream>

hdu 5274 树链剖分

Dylans loves tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1484    Accepted Submission(s): 347 Problem Description Dylans is given a tree with N nodes. All nodes have a value A[i].Nodes

BZOJ 2819 Nim 树链剖分/DFS序+LCA+树状数组

题意:给定一棵树,每个节点是一堆石子,给定两种操作: 1.改变x号节点的石子数量 2.用从x到y的路径上的所有堆石子玩一次Nim游戏,询问是否有必胜策略 Nim游戏有必胜策略的充要条件是所有堆的石子数异或起来不为零 这题首先一看就是树链剖分 然后题目很善良地告诉我们深搜会爆栈 于是我们可以选择广搜版的树链剖分 BFS序从左到右是深搜,从右到左是回溯,一遍BFS就够 单点修改区间查询还可以套用ZKW线段树 不过这题其实不用这么麻烦 有更简单的办法 详见 http://dzy493941464.is

HDU4897 (树链剖分+线段树)

Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作2:将所有 有且仅有一个点在a->b的路径中 的边的颜色翻转. 操作3:询问a->b的路径中的黑色边数量. 解题分析 考虑操作1,只需正常的树链剖分+线段树维护即可.用线段树维护每条边,tag_1[i]表示该区间中的黑色边数量. 考虑操作2,一个节点相邻的边只可能为重链和轻链,且重链的数目小于等于

(树链剖分+线段树)POJ - 3237 Tree

前言: 一直听说树链剖分-树链剖分,现在见识一下,,,感觉不是很难0.0 看了一下kuangbin模板基本秒懂 对于点,按重边优先给予每个点一个编号,对于一条重链上的点,编号则是连续的,将所有编号映射到线段树上,即可进行一切区间操作. 对于边的处理,我们将所有边对应到这条边节点更深的那个点上即可. 如果需要的操作只有求和,和单点更新/区间更新,直接用树状数组也是可以的,可能常数大那么一点点. 如果还需要更加强大的操作,显然用splay树维护也是可以的.. 比如树链上所有权值翻转等等..不过,,这

HDU 5274 Dylans loves tree(LCA+dfs时间戳+成段更新 OR 树链剖分+单点更新)

Problem Description Dylans is given a tree with N nodes. All nodes have a value A[i].Nodes on tree is numbered by 1∼N. Then he is given Q questions like that: ①0 x y:change node x′s value to y ②1 x y:For all the value in the path from x to y,do they

【树链剖分】权值取反,区间最大

[题面] 有一棵n个点的树,边按照1~n-1标号,每条边拥有一个边权 现在有 m 次操作,每次操作为如下三种之一: . 1 x y:边x的权值改为y . 2 x y:将点x到点y路径上的所有边权值变成相反数 . 3 x y:查询点x到点y路径上的最大边权 第一行为两个整数n,m,表示序列长度和操作次数 接下来n-1行,每行三个数a,b,v,表示a,b之间有一条权值为v的边,按照标号1~n-1的顺序给出 接下来m行, 每行以1/2/3作为第一个数,表示操作种类.接下来两个整数,格式如题,表示一次操