P4592 [TJOI2018]异或

题目描述

现在有一颗以\(1\)为根节点的由\(n\)个节点组成的树,树上每个节点上都有一个权值\(v_i\)。现在有\(Q\)次操作,操作如下:

  • 1 x y:查询节点\(x\)的子树中与\(y\)异或结果的最大值

  • 2 x y:查询路径\(x\)到\(y\)上点与\(z\)异或结果最大值

输入输出格式

输入格式:

第一行是两个数字\(n,Q\);

第二行是\(n\)个数字用空格隔开,第\(i\)个数字\(v_i\)表示点\(i\)上的权值

接下来\(n-1\)行,每行两个数,\(x,y\),表示节点\(x\)与\(y\)之间有边

接下来\(Q\)行,每一行为一个查询,格式如上所述.

输出格式:

对于每一个查询,输出一行,表示满足条件的最大值。

说明

对于\(10\%\)的数据,有\(1<n,Q\leq100\)

对于\(20\%\)的数据,有\(1<n,Q\leq1000\)

对于\(40\%\)的数据,有\(1<n,Q\leq10000\)

对于\(100\%\)的数据,有\(1<n,Q\leq100000\)

对于\(100\%\)的数据,有查询\(1\)中的\(y\leq2^{30}\),查询\(2\)中的\(z\leq2^{30}\)。


区间异或最大值可以用可持久化字典树实现。

这个题建对DFS序建一颗,对自根向下的链建,分别处理两种询问就可以了。


Code:

#include <cstdio>
#include <cctype>
const int N=1e5+10;
int read()
{
int x=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) {x=x*10+c-'0';c=getchar();}
return x;
}
int max(int x,int y){return x>y?x:y;}
#define ls ch[now][0]
#define rs ch[now][1]
#define rep(i,a,b) for(int i=a;i<=b;i++)
int head[N],to[N<<1],Next[N<<1],cnt;
void add(int u,int v)
{
to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
int poi[N],n,Q;
namespace work1//子树
{
int ch[N*32][2],mx[N*32],tot,dfn[N],low[N],ha[N],dfsclock,root[N];
void dfs(int now,int fa)
{
dfn[now]=++dfsclock;
ha[dfsclock]=now;
for(int i=head[now];i;i=Next[i])
if(to[i]!=fa)
dfs(to[i],now);
low[now]=dfsclock;
}
void Insert(int las,int &now,int dep,int id)
{
if(!now) now=++tot;
if(dep<0){mx[now]=id;return;}
int bit=poi[ha[id]]>>dep&1;
Insert(ch[las][bit],ch[now][bit],dep-1,id);
ch[now][bit^1]=ch[las][bit^1];
mx[now]=max(mx[ls],mx[rs]);
}
void init()
{
dfs(1,0);
rep(i,1,n) Insert(root[i-1],root[i],30,i);
}
int query(int now,int les,int dep,int x)
{
if(dep<0) return x^poi[ha[mx[now]]];
int bit=x>>dep&1;
if(mx[ch[now][bit^1]]>=les) return query(ch[now][bit^1],les,dep-1,x);
return query(ch[now][bit],les,dep-1,x);
}
void work()
{
int x=read(),y=read();
printf("%d\n",query(root[low[x]],dfn[x],30,y));
}
}
namespace work2
{
int f[N][20],ch[N*32][2],mx[N*32],root[N],dep[N],en[N*32],tot,tmp;
void swap(int &x,int &y){tmp=x,x=y,y=tmp;}
void Insert(int las,int &now,int de,int id)
{
if(!now) now=++tot;
if(de<0){mx[now]=dep[id],en[now]=id;return;}
int bit=poi[id]>>de&1;
Insert(ch[las][bit],ch[now][bit],de-1,id);
ch[now][bit^1]=ch[las][bit^1];
mx[now]=max(mx[ls],mx[rs]);
}
void dfs(int now)
{
for(int i=1;f[now][i-1];i++) f[now][i]=f[f[now][i-1]][i-1];
for(int i=head[now];i;i=Next[i])
{
int v=to[i];
if(v==f[now][0]) continue;
dep[v]=dep[now]+1;
f[v][0]=now;
Insert(root[now],root[v],30,v);
dfs(v);
}
}
void init()
{
dep[1]=1;
Insert(0,root[1],30,1);
dfs(1);
}
int LCA(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=18;~i;i--)
if(dep[f[x][i]]>=dep[y])
x=f[x][i];
if(x==y) return x;
for(int i=18;~i;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
int query(int now,int les,int de,int x)
{
if(de<0) return poi[en[now]]^x;
int bit=x>>de&1;
if(mx[ch[now][bit^1]]>=les) return query(ch[now][bit^1],les,de-1,x);
return query(ch[now][bit],les,de-1,x);
}
void work()
{
int x=read(),y=read(),z=read(),lca=LCA(x,y);
printf("%d\n",max(query(root[x],dep[lca],30,z),query(root[y],dep[lca],30,z)));
}
}
int main()
{
n=read(),Q=read();
rep(i,1,n) scanf("%d",poi+i);
for(int u,v,i=1;i<n;i++)
u=read(),v=read(),add(u,v),add(v,u);
work1::init();
work2::init();
rep(i,1,Q)
{
if(read()==1) work1::work();
else work2::work();
}
return 0;
}

2018.11.3

洛谷 P4592 [TJOI2018]异或 解题报告的更多相关文章

  1. [洛谷P4592][TJOI2018]异或

    题目大意:有一棵$n$个点的树,第$i$个点权值为$w_i$,有两种操作: $1\;x\;y:$询问节点$x$的子树中与$y$异或结果的最大值 $2\;x\;y\;z:$询问路径$x$到$y$上点与$ ...

  2. 洛谷P4592 [TJOI2018]异或(可持久化01Trie)

    题意 题目链接 可持久化01Trie板子题 对于两个操作分别开就行了 #include<bits/stdc++.h> using namespace std; const int MAXN ...

  3. 洛谷P4592 [TJOI2018]异或 【可持久化trie树】

    题目链接 BZOJ4592 题解 可持久化trie树裸题 写完就A了 #include<algorithm> #include<iostream> #include<cs ...

  4. 洛谷_Cx的故事_解题报告_第四题70

    1.并查集求最小生成树 Code: #include <stdio.h> #include <stdlib.h>   struct node {     long x,y,c; ...

  5. 洛谷 P2317 [HNOI2005]星际贸易 解题报告

    P2317 [HNOI2005]星际贸易 题目描述 输入输出格式 输入格式: 输出格式: 如果可以找到这样的方案,那么输出文件output.txt中包含两个整数X和Y.X表示贸易额,Y表示净利润并且两 ...

  6. 洛谷 P3802 小魔女帕琪 解题报告

    P3802 小魔女帕琪 题目背景 从前有一个聪明的小魔女帕琪,兴趣是狩猎吸血鬼. 帕琪能熟练使用七种属性(金.木.水.火.土.日.月)的魔法,除了能使用这么多种属性魔法外,她还能将两种以上属性组合,从 ...

  7. 洛谷 P2606 [ZJOI2010]排列计数 解题报告

    P2606 [ZJOI2010]排列计数 题目描述 称一个\(1,2,...,N\)的排列\(P_1,P_2...,P_n\)是\(Magic\)的,当且仅当对所以的\(2<=i<=N\) ...

  8. 洛谷1303 A*B Problem 解题报告

    洛谷1303 A*B Problem 本题地址:http://www.luogu.org/problem/show?pid=1303 题目描述 求两数的积. 输入输出格式 输入格式: 两个数 输出格式 ...

  9. 洛谷 P4074 [WC2013]糖果公园 解题报告

    P4074 [WC2013]糖果公园 糖果公园 树上待修莫队 注意一个思想,dfn序处理链的方法,必须可以根据类似异或的东西,然后根据lca分两种情况讨论 注意细节 Code: #include &l ...

随机推荐

  1. AIX7.1删除大批量文件(百万级、千万级)

    假设/data/test目录下含有数百万上千万的文件需要删除,可以选择的方式如下: 1.如果文件名不包含空白符.引号等特殊字符,则可以使用如下命令: find /data/test -type f | ...

  2. [JSON].result()

    语法:[JSON].result() 返回:[True | False] 说明:用json字符串创建JSON实例时,如果该json字符串不是合法的json格式,会创建一个空的json实例.但是我们如果 ...

  3. leetcode合并区间

    合并区间     给出一个区间的集合,请合并所有重叠的区间. 示例 1: 输入: [[1,3],[2,6],[8,10],[15,18]] 输出: [[1,6],[8,10],[15,18]] 解释: ...

  4. 日历(Calendar)模块

    #usr/bin/python3 #! -*-conding : utf-8 -*- #2018.3.14 """ 日历(Calendar)模块 此模块的函数都是日历相关 ...

  5. 承压计算:模拟+double

    标题:承压计算 X星球的高科技实验室中整齐地堆放着某批珍贵金属原料. 每块金属原料的外形.尺寸完全一致,但重量不同.金属材料被严格地堆放成金字塔形. 7                         ...

  6. es6从零学习(五):Module的语法

    es6从零学习(五):Module的语法 ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量 一:es6模块化和 CommonJS 和 AMD 模块 (运行 ...

  7. 最全NB-IoT/eMTC物联网解决方案名录汇总

    NB-IoT/eMTC等蜂窝物联网技术的成熟和商用,占据低功耗广域网络(LPWAN)的主流地位,推动全球物联网新一轮发展热潮,越来越多的行业开始采用物联网方案来解决解决实际问题.实现落地应用,越来越多 ...

  8. Simple Expression

    Description You probably know that Alex is a very serious mathematician and he likes to solve seriou ...

  9. block知识总结

    一.block在内存中存在的形式 1.当把block句法写在函数或者方法外面时,系统会在静态数据区分配一块内存区域给block对象.这片区域在程序执行期会一直存在. 2.当block句法写在函数或者方 ...

  10. TCP系列15—重传—5、Linux中RTO的计算

    之前我们介绍的都是协议中给出的RTO计算方法,下面我们看一下linux实现中RTO的计算方法.在linux中维护了srtt.mdev.mdev_max.rttvar.rtt_seq几个状态变量用来计算 ...