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. Newton方法

    Newton方法主要解决无等式约束和等式约束的最优化方法. 1.函数进行二阶泰勒展开近似 Taylor近似函数求导等于0进而得到Newton步径.(搜索方向) 2.Newton减量(停止条件) 当1/ ...

  3. cuda编程-矩阵乘法(2)

    采用shared memory加速 代码 #include <stdio.h> #include <stdlib.h> #include <math.h> #inc ...

  4. LNMP平台部署

    LNAP平台概述 百度百科 LNMP代表的就是:Linux系统下Nginx+MySQL+PHP这种网站服务器架构. Linux是一类Unix计算机操作系统的统称,是目前最流行的免费操作系统.代表版本有 ...

  5. JS获取宽度高度大集合

    网页可见区域宽:document.body.clientWidth 网页可见区域高:document.body.clientHeight 网页可见区域宽:document.body.offsetWid ...

  6. 使用docker部署springboot

    首先创建一个简单的springboot web项目 创建一个 DockerController,在其中有一个index()方法,访问时返回:Hello Docker! @RestController ...

  7. Breakable loop in Scratch

    Breakable loop in Scratch https://stackoverflow.com/questions/30682144/breakable-loop-in-scratch Bre ...

  8. 解决Eclipse每次修改完代码后需要先Clean,不然修改的代码无效

    工具栏 Project-->Build Automatically 勾选上即可

  9. Android sqlitedatabase 事务

    SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction() 方法时会检查事务的标志是否为成功,如果为成功则提交事务,否则回滚事务 ...

  10. 前端开发环境webstorm搭建

    1. 下载node.js https://nodejs.org/en/ 2. 安装 webpack 用管理员开个命令行 (mac: open terminal) npm install webpack ...