https://www.lydsy.com/JudgeOnline/problem.php?id=2819

题意:树上单点修改及区间异或和查询。

思维难度不高,但是题比较硬核。

整体思路是维护每一个结点到根节点的距离。查询u,v树链上的异或和就是query(v) ^ query(u) ^ a[lca(u,v)],所以就要想办法维护树上的结点到根节点的异或和。

网上的题解大多是选择直接维护答案,修改的时候修改整颗子树的答案,用线段树或者树状数组区间异或一下l到r内的答案就可以。

我一开始没有想到直接上lca直接维护根节点的距离,所以在dfs序上见了一颗线段树,查询的时候query 1到u第一次出现地方的异或和,区间的时候常规单点修改也可过。

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
inline int read(){int now=;register char c=getchar();for(;!isdigit(c);c=getchar());
for(;isdigit(c);now=now*+c-'',c=getchar());return now;}
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
const double eps = 1e-;
const int maxn = 5e5 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K;
LL a[maxn];
struct Edge{
int next,to;
}edge[maxn * ];
int head[maxn],tot;
void init(){
for(int i = ; i <= N ; i ++) head[i] = -;
tot = ;
}
void add(int u,int v){
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
const int SP = ;
int pa[maxn][SP],dep[maxn];
//求dfs序
int num;
int dfs_index[maxn * ];
PII pos[maxn];
void dfs(int t,int la){
pa[t][] = la;
dep[t] = dep[la] + ;
for(int i = ; i <= SP - ; i ++) pa[t][i] = pa[pa[t][i - ]][i - ];
pos[t].fi = ++num;
dfs_index[num] = t;
for(int i = head[t]; ~i ; i = edge[i].next){
int v = edge[i].to;
if(v == la) continue;
dfs(v,t);
}
pos[t].se = ++num;
dfs_index[num] = t;
}
int lca(int u,int v){
if(dep[u] < dep[v]) swap(u,v);
int t = dep[u] - dep[v];
for(int i = ; i <= SP - ; i ++){
if(t & ( << i)) u = pa[u][i];
}
for(int i = SP - ; i >= ; i --){
int uu = pa[u][i],vv = pa[v][i];
if(uu != vv){
u = uu;
v = vv;
}
}
return u == v? u :pa[u][];
}
//线段树
struct Tree{
LL sum;
}tree[maxn << ];
void Pushup(int t){
tree[t].sum = tree[t << ].sum ^ tree[t << | ].sum;
}
void Build(int t,int l,int r){
if(l == r){
tree[t].sum = a[dfs_index[l]];
return;
}
int m = (l + r) >> ;
Build(t << ,l,m); Build(t << | ,m + ,r);
Pushup(t);
}
void update(int t,int p,int x,int L,int R){
if(L == R){
tree[t].sum = x;
return;
}
int m = (L + R) >> ;
if(p <= m) update(t << ,p,x,L,m);
else update(t << | ,p,x,m + ,R);
Pushup(t);
}
LL query(int t,int l,int r,int L,int R){
if(l <= L && R <= r){
return tree[t].sum;
}
int m = (L + R) >> ;
if(r <= m) return query(t << ,l,r,L,m);
else if(l > m) return query(t << | ,l,r,m + ,R);
else return query(t << ,l,m,L,m) ^ query(t << | ,m + ,r,m + ,R);
} LL query(int x){
return query(,,pos[x].fi,, * N);
}
int main(){
Sca(N); init();
For(i,,N) Scl(a[i]);
For(i,,N - ){
int u,v; Sca2(u,v);
add(u,v); add(v,u);
}
dfs(,);
Build(,, * N);
Sca(K);
while(K--){
char op[];
int u,v;
scanf("%s%d%d",op,&u,&v);
if(op[] == 'Q'){
if(query(u) ^ query(v) ^ a[lca(u,v)]) puts("Yes");
else puts("No");
}else{
update(,pos[u].fi,v,, * N);
update(,pos[u].se,v,, * N);
a[u] = v;
}
}
return ;
}

bzoj2819 DFS序 + LCA + 线段树的更多相关文章

  1. bzoj3306: 树(dfs序+倍增+线段树)

    比较傻逼的一道题... 显然求子树最小值就是求出dfs序用线段树维护嘛 换根的时候树的形态不会改变,所以我们可以根据相对于根的位置分类讨论. 如果询问的x是根就直接输出整棵树的最小值. 如果询问的x是 ...

  2. Codeforces 877E - Danil and a Part-time Job(dfs序+线段树)

    877E - Danil and a Part-time Job 思路:dfs序+线段树 dfs序:http://blog.csdn.net/qq_24489717/article/details/5 ...

  3. 用dfs序处理线段树的好题吗?

    https://www.cnblogs.com/mountaink/p/9878918.html 分析:每次的选取必须选最优的一条链,那我们考虑一下选择这条链后,把这条路上的点的权值更新掉,再采取选最 ...

  4. 7月13日考试 题解(DFS序+期望+线段树优化建图)

    T1 sign 题目大意:给出一棵 N 个节点的树,求所有起点为叶节点的有向路径,其 上每一条边权值和的和.N<=10000 水题.考试的时候毒瘤出题人(学长orz)把读入顺序改了一下,于是很多 ...

  5. hdu 3974 Assign the task(dfs序上线段树)

    Problem Description There is a company that has N employees(numbered from 1 to N),every employee in ...

  6. Luogu P2982 [USACO10FEB]慢下来 Slowing down | dfs序、线段树

    题目链接 题目大意: 有一棵N个结点树和N头奶牛,一开始所有奶牛都在一号结点,奶牛们将按从编号1到编号N的顺序依次前往自己的目的地,求每头奶牛在去往自己目的地的途中将会经过多少已经有奶牛的结点. 题解 ...

  7. Codeforces Round #200 (Div. 1) D. Water Tree(dfs序加线段树)

    思路: dfs序其实是很水的东西.  和树链剖分一样, 都是对树链的hash. 该题做法是:每次对子树全部赋值为1,对一个点赋值为0,查询子树最小值. 该题需要注意的是:当我们对一棵子树全都赋值为1的 ...

  8. hdu4366 Successor (dfs序+zkw线段树)

    Successor Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total S ...

  9. URAL 1890 . Money out of Thin Air (dfs序hash + 线段树)

    题目链接: URAL 1890 . Money out of Thin Air 题目描述: 给出一个公司里面上司和下级的附属关系,还有每一个人的工资,然后有两种询问: 1:employee x y z ...

随机推荐

  1. source 和 .

    Linux Source命令及脚本的执行方式解析 当我修改了/etc/profile文件,我想让它立刻生效,而不用重新登录:这时就想到用source命令,如:source /etc/profile 对 ...

  2. sed命令参数之-r -i

    对于初学linux的朋友来说,能记住命令附带的一大帮参数就以及非常不容易了.好不容易把该用的参数都想全了.sed -irns 后面一大片脚本 ,一执行出错了 what!!!! 创建一下测试环境 hea ...

  3. vhdl 边沿

    rising_eage falling_eage clock'event and clock='1' 两种方式

  4. JSED204B

    简介 JESD204是一种连接数据转换器(ADC和DAC)和逻辑器件的高速串行接口,该标准的 B 修订版支持高达 12.5 Gbps串行数据速率,并可确保 JESD204 链路具有可重复的确定性延迟. ...

  5. codeforces616B

    Dinner with Emma CodeForces - 616B Jack decides to invite Emma out for a dinner. Jack is a modest st ...

  6. 最简单的socket服务器与客户端

    服务器: //服务器 #include <stdio.h> #include <netinet/in.h> #include <unistd.h> #include ...

  7. Linux编译静态库与共享库

    静态库: cc  -c   mod1.c  mod2.c //编译 ar   r     libdemo.a   mod1.o   mod2.o //生成静态库 cc  -c   prog.c //编 ...

  8. linux下后台启动springboot项目

    linux下后台启动springboot项目 我们知道启动springboot的项目有三种方式: 运行主方法启动 使用命令 mvn spring-boot:run”在命令行启动该应用 运行“mvn p ...

  9. CH2601 电路维修(算竞进阶习题)

    01边bfs 这题很容易想到的就是根据符号的情况建图,把每个点方格的对角线看成图的节点,有线相连就是边权就是0,没有就是1 然后跑最短路,但是最短路用的优先队列维护是有logn的代价的 这题还有一个更 ...

  10. 「UVA10766」Organising the Organisation(生成树计数)

    BUPT 2017 Summer Training (for 16) #6C 题意 n个点,完全图减去m条边,求生成树个数. 题解 注意可能会给重边. 然后就是生成树计数了. 代码 #include ...