从lca到树链剖分 bestcoder round#45 1003
bestcoder round#45 1003 题,给定两个点,要我们求这两个点的树上路径所经过的点的权值是否出现过奇数次。
如果是一般人,那么就是用lca求树上路径,然后判断是否出现过奇数次(用异或),高手就不这么做了,直接树链剖分。
为什么不能用lca,因为如果有树退化成链,那么每次询问的复杂度是O(n), 那么q次询问的时间复杂度是O(qn)
什么是树链剖分呢? 就是把树的边分成轻链和重链
http://blog.sina
.com.cn/s/blog_6974c8b20100zc61.html
http://www.cnblogs
.com/BLADEVIL/p/3479713.html
这两个博客写的很好了
剖分后的树有如下性质:
1、如果(u,v)为轻边, 那么 size[v]*2<size[u]
2、从根到某一点的路径上的轻链,重链的个数不大于logn
所以我们可以用线段树来维护这些链,这样如果 要得到任意两点树上路径的信息,那么只要访问线段树,那么时间复杂度只要4logn*logn
第一次dfs进行树链剖分,求出了轻链和重链
第二次dfs对树的结点进行了重新编号(结点的编号就是在线段树中区间中的一点), 重链上的结点的编号是连续的
那么重链上的点在线段树中的区间是连续的。
那么要询问树上任意两点路径权值的最大值, 只要上depth大的那个点往上走, 如果往上走的时候,遇到的重链,那么可以进去区间查询,然后一次
走过重链即可。
对于bestcoder round#45 1003 题,
第二次dfs求出编号后,建线段树,然后区间的值等于子区间的异或
那么任意两点的树上路径的权值是否重复,只要访问线段树区间,看最后的异或的值是为0
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#pragma warning(disable:4996)
typedef long long LL;
const int INF = <<;
void input(int &x)
{
char ch = getchar();
while (ch<'' || ch>'')
ch = getchar();
x = ;
while (ch >= ''&&ch <= '')
{
x = x * + ch - '';
ch = getchar();
}
}
/*
第一次dfs进行树链剖分,求出了轻链和重链
第二次dfs对树的结点进行了重新编号, 重链上的结点的编号是连续的
那么重链上的点在线段树中的区间是连续的
剖分后的树有如下性质:
性质1:如果(v,u)为轻边,则siz[u] * 2 < siz[v];
性质2:从根到某一点的路径上轻链、重链的个数都不大于logn。 那么要询问树上任意两点路径权值的最大值, 只要上depth大的那个点往上走, 如果往上走的时候,遇到的重链,那么可以进去区间查询,然后一次
走过重链
根据性质2:每次询问的复杂度是O(logn*logn)
*/
const int N = + ;
int size[N], depth[N], son[N], fa[N], w[N], top[N], ra[N], num;
int value[N];
int tree[N * ];
vector<int> g[N];
int ans;
void dfs(int u)
{
size[u] = ;
son[u] = ;
for (int i = ; i < g[u].size(); ++i)
{
int v = g[u][i];
if (v != fa[u])
{
depth[v] = depth[u] + ;
fa[v] = u;
dfs(v);
size[u] += size[v];
if (size[v]>size[son[u]])
son[u] = v;
}
}
}
void dfs2(int u, int tp)
{
top[u] = tp;
w[u] = ++num;//对树上的结点进行编号
ra[num] = u;
//因为优先dfs重儿子,所以一条重链上的点的编号是连续的
if (son[u] != )
dfs2(son[u], top[u]);
for (int i = ; i < g[u].size(); ++i)
{
int v = g[u][i];
if (v != son[u] && v != fa[u])
dfs2(v, v);
}
}
void pushUp(int rt)
{
tree[rt] = tree[rt << ] ^ tree[rt << | ];
}
void build(int l, int r, int rt)
{
if (l == r)
{
tree[rt] = value[ra[l]];//ra[l] 是编号为l的是哪个结点
return;
}
int mid = (l + r) >> ;
build(l, mid, rt << );
build(mid + , r, rt << | );
pushUp(rt);
}
//修改某个结点的值, 那么要将父区间异或旧的值(即去除原先的值),然后异或新的值
void update(int l, int r, int rt, int pos, int newVal, int oldVal)
{
tree[rt] = tree[rt] ^ oldVal^newVal;
if (l == r)
return;
int mid = (l + r) >> ;
if (pos <= mid)
update(l, mid, rt << , pos, newVal, oldVal);
else
update(mid + , r, rt << | , pos, newVal, oldVal);
}
void query(int l, int r, int rt, int L, int R)
{
if (L <= l && R >= r)
{
ans ^= tree[rt];
return;
}
int mid = (l + r) >> ;
if (L <= mid)
query(l, mid, rt << , L, R);
if (R > mid)
query(mid + , r, rt << | , L, R);
}
int main()
{
int t, n, q, op,a, b;
scanf("%d", &t);
while (t--)
{
num = ;
scanf("%d%d", &n, &q);
for (int i = ; i <= n; ++i)
g[i].clear();
for (int i = ; i < n; ++i)
{
scanf("%d%d", &a, &b);
g[a].push_back(b);
g[b].push_back(a);
}
for (int i = ; i <= n; ++i)
{
//scanf("%d", &value[i]);
input(value[i]);
value[i]++;
}
depth[] = fa[] = ;
dfs();
dfs2(, );
build(, n, );
while (q--)
{
scanf("%d%d%d", &op, &a, &b); if (op == )
{
b++;
update(, n, , w[a], b, value[a]);
value[a] = b;
}
else
{
ans = ;
//不停的往上走,像lca一样,不过比lca更优,因为有重链的存在,可以一次走很多部
while (top[a] != top[b])
{
if (depth[top[a]] < depth[top[b]])
swap(a, b);
query(, n, , w[top[a]], w[a]);
a = fa[top[a]];
}
if (depth[a] > depth[b])
swap(a, b);
query(, n, , w[a], w[b]);
if (ans == )
printf("%d\n", -);
else
printf("%d\n", ans - );
}
}
}
return ;
}
从lca到树链剖分 bestcoder round#45 1003的更多相关文章
- 【BZOJ3626】LCA(树链剖分,Link-Cut Tree)
[BZOJ3626]LCA(树链剖分,Link-Cut Tree) 题面 Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. ...
- LCA 倍增||树链剖分
方法1:倍增 1498ms #include <iostream> #include <cstdio> #include <algorithm> #include ...
- uva 12655 Trucks [LCA](树链剖分+MST)
The Subtle Balloons Company (SBC) is the main balloon provider for programming contests; it hashuge ...
- CF 191C Fools and Roads lca 或者 树链剖分
They say that Berland has exactly two problems, fools and roads. Besides, Berland has n cities, popu ...
- P3379 【模板】最近公共祖先(LCA)(树链剖分)版
#include <bits/stdc++.h> #define read read() #define up(i,l,r) for(register int i = (l);i < ...
- 2018.09.16 bzoj3626: [LNOI2014]LCA(树链剖分)
传送门 树链剖分好题. 对于每个点维护一个值vi" role="presentation" style="position: relative;"&g ...
- BZOJ 3626 LCA(离线+树链剖分)
首先注意到这样一个事实. 树上两个点(u,v)的LCA的深度,可以转化为先将u到根路径点权都加1,然后求v到根路径上的总点权值. 并且该题支持离线.那么我们可以把一个区间询问拆成两个前缀和形式的询问. ...
- JZYZOJ1454 NOIP2015 D2T3_运输计划 二分 差分数组 lca tarjan 树链剖分
http://172.20.6.3/Problem_Show.asp?id=1454 从这道题我充分认识到我的脑子里好多水orz. 如果知道了这个要用二分和差分写,就没什么思考上的难点了(屁咧你写了一 ...
- BZOJ3626: [LNOI2014]LCA(树链剖分+线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...
随机推荐
- ExtJs4 笔记(12) Ext.toolbar.Toolbar 工具栏、Ext.toolbar.Paging 分页栏、Ext.ux.statusbar.StatusBar 状态栏
本篇讲解三个工具栏控件.其中Ext.toolbar.Toolbar可以用来放置一些工具类操控按钮和菜单,Ext.toolbar.Paging专门用来控制数据集的分页展示,Ext.ux.statusba ...
- 熬之滴水穿石:JSP--HTML中的JAVA代码(6)
39--JSTL 在JSP编码中需考虑的一种方法,因为这种方法可以 ...
- CocoaPods的install和update卡在“Anylyzing dependencies”的问题解决方式[效率]
问题 最新CocoaPod更新慢得问题,不管是运行pod install还是podupdate都卡在Anylyzing dependencies. 解决方式 事实上原因是运行两个命令时都会升级Coco ...
- Qt 向word中插入文字(使用QAxWidget和QAxObject)
pro 文件中要加入 CONFIG += qaxcontainer 2. main.cpp #include <QApplication> #include <QAxWidget&g ...
- Android Studio之同一窗口打开项目
Android Studio默认新打开的项目都是重新打开一个窗口,和原项目窗口同时存在,如果打开多个项目,则有很多窗口同时打开,怎么根据需要决定自己以何种方式打开呢? 1.设置打开新项目的方式 第一项 ...
- C++经典笔试题及参考答案-趋势科技
1.static有什么用途?(请至少说明两种) 答案:1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变. 2)在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数 ...
- 腾讯文学动作密集 疑为手Q发力移动阅读铺路
移动互联网的门票之争并未结束,百度收购91无线,阿里投资新浪微博.UC浏览器,网易推易信.云音乐等等,都是互联网巨头争夺移动互联网门票的最佳案例.不过,上述任何巨头都不可忽视腾讯这个“狠角色” ...
- Matlab实现Hough变换检測图像中的直线
Hough变换的原理: 将图像从图像空间变换至參数空间.变换公式例如以下: 变换以后,图像空间与參数空间存在下面关系: 图像空间中的一点在參数空间是一条曲线,而图像空间共线的各点相应于參数空间交于一点 ...
- [docker]docker的四种网络方式
声明: 本博客欢迎转发,但请保留原作者信息! 博客地址:http://blog.csdn.net/halcyonbaby 内容系本人学习.研究和总结,如有雷同,实属荣幸! bridge方式(默认) H ...
- WM_NCHITTEST有21种取值,常用的有HTCAPTION,HTCLIENT,HTBORDER,HTSYSMENU,HTTRANSPARENT,罗列所有VCL里对其使用的情况
我为了移动一个无标题栏的窗体,使用了WM_NCHITTEST消息,这个消息大概如下: 通常,我们拖动对话框窗口的标题栏来移动窗口,但有时候,我们想通过鼠标在客户区上拖动来移动窗口. 一个容易想到的方案 ...