bzoj2819 DFS序 + LCA + 线段树
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 + 线段树的更多相关文章
- bzoj3306: 树(dfs序+倍增+线段树)
比较傻逼的一道题... 显然求子树最小值就是求出dfs序用线段树维护嘛 换根的时候树的形态不会改变,所以我们可以根据相对于根的位置分类讨论. 如果询问的x是根就直接输出整棵树的最小值. 如果询问的x是 ...
- 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 ...
- 用dfs序处理线段树的好题吗?
https://www.cnblogs.com/mountaink/p/9878918.html 分析:每次的选取必须选最优的一条链,那我们考虑一下选择这条链后,把这条路上的点的权值更新掉,再采取选最 ...
- 7月13日考试 题解(DFS序+期望+线段树优化建图)
T1 sign 题目大意:给出一棵 N 个节点的树,求所有起点为叶节点的有向路径,其 上每一条边权值和的和.N<=10000 水题.考试的时候毒瘤出题人(学长orz)把读入顺序改了一下,于是很多 ...
- hdu 3974 Assign the task(dfs序上线段树)
Problem Description There is a company that has N employees(numbered from 1 to N),every employee in ...
- Luogu P2982 [USACO10FEB]慢下来 Slowing down | dfs序、线段树
题目链接 题目大意: 有一棵N个结点树和N头奶牛,一开始所有奶牛都在一号结点,奶牛们将按从编号1到编号N的顺序依次前往自己的目的地,求每头奶牛在去往自己目的地的途中将会经过多少已经有奶牛的结点. 题解 ...
- Codeforces Round #200 (Div. 1) D. Water Tree(dfs序加线段树)
思路: dfs序其实是很水的东西. 和树链剖分一样, 都是对树链的hash. 该题做法是:每次对子树全部赋值为1,对一个点赋值为0,查询子树最小值. 该题需要注意的是:当我们对一棵子树全都赋值为1的 ...
- hdu4366 Successor (dfs序+zkw线段树)
Successor Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total S ...
- URAL 1890 . Money out of Thin Air (dfs序hash + 线段树)
题目链接: URAL 1890 . Money out of Thin Air 题目描述: 给出一个公司里面上司和下级的附属关系,还有每一个人的工资,然后有两种询问: 1:employee x y z ...
随机推荐
- 打包一个UWP APP
Before packaging your app Test your app. Before you package your app for store submission, make sure ...
- CF 1041 1042整理
终于回来整理了,这两场比赛我也是醉了,第一场-1分,第二场被skip,还是太菜啊qaq CF1041 T1T2过水忽略直接看后面 T3大意:给你一个长度为n的序列a1,a2,a3···an,你需要把这 ...
- Python操作Memcached
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度.Memcached ...
- MySQL参数调优
目录 连接相关参数 文件相关参数 缓存相关参数 MyISAM参数 InnoDB参数 连接相关参数 max_connections 允许客户端并发连接的最大数量,默认值是151,一般将该参数设置为50 ...
- BZOJ3438小M的作物——最小割
题目描述 小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子 有1个(就是可以种一棵作物)(用1...n编号),现在,第i种作物种植在A中种植可 ...
- Educational Codeforces Round 62 (Rated for Div. 2)
A. Detective Book 题意:一个人读书 给出每一章埋的坑在第几页可以填完 . 一个人一天如果不填完坑他就会一直看 问几天能把这本书看完 思路:模拟一下 取一下过程中最大的坑的页数 如 ...
- Cash Machine POJ - 1276 多重背包二进制优化
题意:多重背包模型 n种物品 每个m个 问背包容量下最多拿多少 这里要用二进制优化不然会超时 #include<iostream> #include<cstdio> #in ...
- 洛谷P1462通往奥格瑞玛的道路题解
[题目]: https://www.luogu.org/problemnew/show/P1462 题意 题目是给定了一张双向边,有边权的图,然后让我们求出一个最小值,满足一条路径上的最大的费用小于这 ...
- 【BZOJ1013】【JSOI2008】球形空间产生器 高斯消元
题目描述 有一个\(n\)维空间中的球,告诉你球面上\(n+1\)个点的坐标,求球心的坐标. \(n\leq 10\) 题解 设\(a_{i,j}\)为第\(i\)个点的第\(j\)维坐标,\(i=0 ...
- python学习日记(流程控制习题)
请输出1-2+3...+99除88以外的和 i = 1 sum = 0 while i <= 99: if i == 88: i = i + 1 continue else: if i%2 == ...