树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询

思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几条链 那么就是对一群区间进行更改 这时候基本是用线段树进行logn的操作

做了三道基础题 都属于比较好想的 也就是线段树比较麻烦 需要写相当长一段时间...

HDU 3966

给出一棵树的连接状况和边的大小 每次可以对a-b的路径的边的权值取反 或者改变指定边的值 或者求a-b路径的最大值

每次取反 最大值就是原最小值*-1 这样维护下去就好

POJ 3237

给出一棵树的连接状况和点的初始值 每次对a-b的路径上的点权进行加减 询问单点大小

树状数组会超时 只能用线段树...需要注意的是点权和边权在树链剖分的时候会有一点不同 例如 u == v  是否return 等

HYSBZ 2243

总觉得以前见过的样子..

给出一棵树的连接状况和边的初始颜色 每次可以对a-b的路径上的边进行更改颜色

最后求a-b路径上的颜色段个数

可以由线段树的本质来看 每个区间的两个子区间 都是从这个线段树一分为2

那么 一个区间内有多少个颜色段数 就等于他的两个子区间的颜色加起来 如果子区间相邻的点颜色相同 那么久减去一

可以在tr数组中记录这个区间的mlmr 即中点两边的点的颜色

每次记录下来前一条链的尾颜色 和当前链的头颜色进行对比 如果相同 就减一

最后当f1 == f2的时候 要同时对比ys1和ys2

交换uv的时候 ys1和ys2也需要交换

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<iostream>
#include<string>
#include<vector>
using namespace std;
#define L long longvector<int >q[100050];int p[100050];
int fp[100050];
int fa[100050];
int son[100050];
int deep[100050];
int top[100050];
int num[100050];
int n , m , pp;
int pos;
void init(){for(int i= 1;i<=n;i++){q[i].clear();}memset(son , -1 ,sizeof(son));pos = 0;
}
int in[100050];
void dfs(int u , int pre , int d){deep[u] = d;fa[u] = pre;num[u] = 1;for(int i = 0;i<q[u].size();i++){int v = q[u][i];if(v != pre){dfs(v,u,d+1);num[u] += num[v];if(son[u] == -1 || num[v] > num[son[u]]){son[u] = v;}}}
}void dfs2(int u , int zx){top[u] = zx;p[u] = pos ++;fp[pos - 1] = u;if(son[u] == -1){return ;}dfs2(son[u],zx);for(int i = 0;i<q[u].size();i++){int v = q[u][i];if(v != fa[u] && v != son[u]){dfs2(v,v);}}
}
/**
线段树 1求一个区间内有多少个颜色 2求一个点的颜色
2直接写查询
1记录这个区间的 中间的两个的颜色
*/
struct node{int l,r;int ml;int mr;int ll ;int rr ;int mark;int d;
}tr[100050 * 4];
void pushup(int i){if(tr[i].l == tr[i].r)return ;tr[i].ll = tr[i<<1].ll;tr[i].rr = tr[(i<<1)|1].rr ;tr[i].ml = tr[i<<1].rr;tr[i].mr = tr[(i<<1)|1].ll ;tr[i].d = tr[i<<1].d + tr[(i<<1)|1].d ;if(tr[i<<1].rr == tr[(i<<1)|1].ll)tr[i].d -- ;
}
void pushdown(int i){if(tr[i].l == tr[i].r)return ;if(tr[i].mark != 0){tr[i<<1].mark = tr[(i<<1)|1].mark = tr[i].mark ;tr[i<<1].ll = tr[i<<1].rr = tr[i<<1].ml = tr[i<<1].mr = tr[i].mark;tr[(i<<1)|1].ll = tr[(i<<1)|1].rr = tr[(i<<1)|1].ml = tr[(i<<1)|1].mr = tr[i].mark;tr[i<<1].d= tr[(i<<1)|1].d = 1;tr[i].mark = 0;}
}
void crea(int i , int l , int r){tr[i].l = l ;tr[i].r = r;tr[i].ml = tr[i].mr = tr[i].ll = tr[i].rr = tr[i].mark = 0;if(l == r){tr[i].ml = tr[i].mr = tr[i].ll = tr[i].rr = in[fp[l]];tr[i].d = 1;return ;}int mid = (l + r )/ 2;crea(i<<1,l,mid);crea((i<<1)|1,mid+1,r);pushup(i);
}
int res ;
void upda(int i ,int l ,int r , int c){if(tr[i].l ==l && r == tr[i].r){tr[i].ml = tr[i].mr = tr[i].ll = tr[i].rr = tr[i].mark = c;tr[i].d = 1;return ;}pushdown(i);int mid = (tr[i].l + tr[i].r) / 2;if(r <= mid){upda(i<<1,l,r,c);}else if(l > mid){upda((i<<1)|1,l,r,c);}else {upda(i<<1,l,mid,c);upda((i<<1)|1,mid+1,r,c);}pushup(i);
}
int query(int i ,int l ,int r){if(tr[i].l == l && r == tr[i].r){return tr[i].d;}pushdown(i);int mid = (tr[i].l + tr[i].r) / 2;if(r <= mid){return query(i<<1,l,r);}else if(l > mid){return query((i<<1)|1,l,r);}else {if(tr[i].ml == tr[i].mr){return query(i<<1,l,mid) + query((i<<1)|1,mid+1,r) - 1;}else {return query(i<<1,l,mid) + query((i<<1)|1,mid+1,r);}}
}
int qu2(int i ,int pos){if(tr[i].l == tr[i].r){return tr[i].ml ;}pushdown(i);int mid = (tr[i].l + tr[i].r) / 2;if(pos <= mid){return qu2(i<<1,pos);}else {return qu2((i<<1)|1,pos);}
}
void did(int u , int v, int c){int f1 = top[u];int f2 = top[v];while(f1 != f2){if(deep[f1] < deep[f2]){swap(f1,f2);swap(u,v);}upda(1,p[f1],p[u],c);u = fa[f1];f1 = top[u];}if(deep[u] < deep[v]){swap(u,v);}upda(1,p[v],p[u],c);
}
int slpf(int u, int v){int ans = 0;int f1 = top[u];int f2 = top[v];int ys1 = -1;int ys2 = -1;while(f1 != f2){if(deep[f1] < deep[f2]){swap(u,v);swap(f1,f2);swap(ys1,ys2);}ans += query(1,p[f1],p[u]);if(ys1 == qu2(1,p[u])){ans -- ;}ys1 = qu2(1,p[f1]);u = fa[f1];f1 = top[u];//printf("%d\n",ans);}if(deep[u] < deep[v]){swap(u,v);swap(ys1,ys2); /// --------}ans += query(1,p[v],p[u]);if(ys1==qu2(1,p[u])){ans -- ;}if(ys2==qu2(1,p[v])){ans -- ;}return ans ;
}
int main(){//freopen("in.cpp","r",stdin);while(scanf("%d%d",&n,&pp)!=EOF){init();for(int i=1;i<=n;i++){scanf("%d",&in[i]);}for(int i=1;i<=n-1;i++){int u , v;scanf("%d%d",&u,&v);q[u].push_back(v);q[v].push_back(u);}dfs(1,0,0);dfs2(1,1);crea(1,0,pos-1);for(int i=1;i<=pp;i++){char s[20];scanf("%s",s);if(s[0] == 'C'){int u , v, c;scanf("%d%d%d",&u,&v,&c);did(u,v,c);}else {int u,v;scanf("%d%d",&u,&v);printf("%d\n",slpf(u,v));}}}
}

感觉树链剖分的主要难点在于线段树的构造...

2017.3.18 很久后又做了一道树链剖分 当然LCA也可做

询问树上路径可否组成三角形 利用斐波那契的思想 由于每一条路径的len<=1e9 所以当路径的条数超过64左右的时候肯定是可以的

当小于64的时候拿出来直接暴力就可以了

树链剖分中 u与top[u] 是连着的 在这里 用a[u]存放 u到fa[u] 的边的权值

所以top[u] -> fa[top[u]] 其实是不在 u -> f1 这条链上的 但是之后会发生 u = fa[f1] 直接翻到这条边上去

所以如果top[u] -> fa[top[u]] 这个边不在路径中 是会直接发生 f1 == f2 的

所以这样记录是不会出现什么问题的 QAQ

好久不写 好麻烦...Orz

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<iostream>
#include<string>
#include<vector>
#include<queue>
using namespace std;
#define L long longconst int maxn = 100050 ;int top[maxn] , fa[maxn] , deep[maxn] , num[maxn] , p[maxn] , fp[maxn] , son[maxn] ;
int pos ;
int n ;
int a[maxn] ;
bool can ;vector<int > q[maxn] ;
vector<int > w[maxn] ;vector<int > tmp ;void init() {pos = 1 ;memset(son , -1 , sizeof(son)) ;for(int i = 1 ; i <= n ; i ++ ) q[i].clear() ;for(int i = 1 ; i <= n ; i ++ ) w[i].clear() ;
}void dfs1(int u , int pre , int d) {deep[u] = d ;fa[u] = pre ;num[u] = 1 ;for(int i = 0 ; i < q[u].size() ; i ++ ){int v = q[u][i] ;if(v != pre) {a[v] = w[u][i] ;dfs1(v,u,d+1);if(son[u] == -1 || num[v] > num[son[u]]) {son[u] = v ;}}}
}void getpos(int u , int sp) {top[u] = sp ;p[u] = pos ++ ;fp[p[u]] = u ;if(son[u] == -1) return ;getpos(son[u] , sp) ;for(int i = 0 ; i < q[u].size() ; i ++ ){int v = q[u][i];if(v != son[u] && v != fa[u]) {getpos(v,v) ;}}
}void slpf(int u ,int v ) {int f1 = top[u] , f2 = top[v] ;int sl = 0 ;while(f1 != f2) {if(deep[f1] < deep[f2]) {swap(f1 , f2) ;swap(u , v) ;}sl += ( p[u] - p[f1] + 1) ;if(sl > 65) {can = false ;return ;}else {for(int i = p[f1] ; i <= p[u] ; i ++ ){tmp.push_back(a[fp[i]]) ;}}u = fa[f1] ;f1 = top[u] ;}if(u == v) return ;if(deep[u] > deep[v]) swap(u , v) ;sl += (p[v] - p[son[u]] + 1) ;if(sl > 65) {can = false ;return ;}for(int i = p[son[u]] ; i <= p[v] ; i ++ ){tmp.push_back(a[fp[i]]) ;}
}int main(){while(scanf("%d" , &n) != EOF) {init() ;for(int i = 1 ; i < n ; i ++ ){int u , v , c ;scanf("%d%d%d",&u,&v,&c) ;q[u].push_back(v) ;q[v].push_back(u) ;w[u].push_back(c) ;w[v].push_back(c) ;}dfs1(1,0,0) ;getpos(1,1) ;a[1] = -9999999 ;int query ;scanf("%d",&query) ;for(int i = 1 ; i <= query ; i ++ ){int u , v ;scanf("%d%d",&u,&v) ;tmp.clear() ;can = true ;slpf(u , v) ;if(can == false) {printf("Yes\n") ;}else {sort(tmp.begin() , tmp.end()) ;bool ok = false ;if(tmp.size() < 3) {}else {for(int j = 2 ; j < tmp.size() ; j ++ ){int aa = tmp[j-2] ;int bb = tmp[j-1] ;int cc = tmp[j] ;if(aa + bb > cc) {ok=true;break ;}}}if(ok)printf("Yes\n");else printf("No\n") ;}}}
}

  

转载于:https://www.cnblogs.com/rayrayrainrain/p/6052293.html

HDU 3966 POJ 3237 HYSBZ 2243 HRBUST 2064 树链剖分相关推荐

  1. BZOJ 2243 染色(树链剖分好题)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 7971  Solved: 2990 [Submit][Stat ...

  2. POJ 3237 Tree (树链剖分)

    Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 2825   Accepted: 769 Description ...

  3. HDU - 3966 Aragorn's Story(树链剖分)

    题目传送门:HDU - 3966 Aragorn's Story 题目大意: 存在一个树,树上每个节点为一个阵营,阵营中存在敌人,现在要进行以下操作 I  C1  C2  K :将阵营C1到阵营C2路 ...

  4. hdu 3966(树链剖分+线段树区间更新)

    传送门:Problem 3966 https://www.cnblogs.com/violet-acmer/p/9711441.html 学习资料: [1]线段树区间更新:https://blog.c ...

  5. POJ 3237 Tree (树链剖分 路径剖分 线段树的lazy标记)

    题目链接:http://poj.org/problem?id=3237 一棵有边权的树,有3种操作. 树链剖分+线段树lazy标记.lazy为0表示没更新区间或者区间更新了2的倍数次,1表示为更新,每 ...

  6. POJ 3237.Tree -树链剖分(边权)(边值更新、路径边权最值、区间标记)贴个板子备忘...

    Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 12247   Accepted: 3151 Descriptio ...

  7. HDU 5274 Dylans loves tree(树链剖分)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5274 [题目大意] 给出一棵树,每个点有一个权值,权值可修改,且大于等于0,询问链上出现次数为奇数 ...

  8. HYSBZ - 2157树链剖分

    [题目描述] HYSBZ - 2157树链剖分 [题目分析] 这道题给出的是边权而不是点权,但是我们分析这个树就会发现每个节点都只有一个父亲,也就是每条边的边权都可以存放在儿子节点上,然后在遍历路径的 ...

  9. 树链剖分入门+HYSBZ - 1036树的统计Count

    今天学习了树链剖分,记录一下. [题目背景] HYSBZ - 1036树的统计Count [题目分析] 题目要求求任意结点之间路径的和以及路径上最大的结点,还有可能修改.如果正常做可能会很复杂(我也不 ...

最新文章

  1. 清华《摸鱼学导论》开课啦!1000多学子在线摸鱼,开课老师为大一新生
  2. 从晶体管特性曲线看饱和问题(Z)
  3. 浅谈Java多线程同步机制之同步块(方法)——synchronized
  4. 关于在asp.net中textbox文本输入框中的汉语标点符号显示位置的问题
  5. 克鲁斯卡尔算法c语言,Kruskal算法(一)之 C语言详解
  6. springboot requestmapping 正则_SpringBoot三招组合拳,手把手教你打出优雅的后端接口...
  7. 【渝粤教育】国家开放大学2018年秋季 0365-21T电子商务概论 参考试题
  8. Hbase与pegasus对比
  9. Hadoop大数据平台构建与应用
  10. 校园网下,虚拟机IP与主机IP不一致及nfs挂载
  11. IE5,IE6,IE7,IE8的css兼容性列表
  12. 一年的网络学习经历小结
  13. Windows 优质软件
  14. html li 圆点 大小,ul li 定制圆点,list-style-image调整图片圆点大小 与 文字和图片排版...
  15. 100+个数据分析常用指标和术语
  16. Linux平台基于poll实现网络编程IO多路复用
  17. 如何实现视频加密全平台播放
  18. 几个数字的组合方式种类个数
  19. ​predis操作大全​
  20. Fvxadvvcssxcvhbnbsaqwerhnvdcnmklllppppppppoooooootretyhgftjhhhfrttyhrxz

热门文章

  1. 【NLP模型笔记】GloVe模型简介
  2. unbuntu 下GTX1660Ti安装显卡驱动
  3. 使用keil5编写stm32代码,用JTAG 仿真器下载代码时,提示cannot load flash device description!解决办法
  4. 字节跳动再“进攻”印度市场,口碑本就不尽人意,这次会顺利吗?
  5. 无人机航拍图像匹配——SIFT算法实践(含代码)
  6. 通过Kmeans聚类算法分析行业价格给商品定价
  7. ZTESoft 持续集成 编年史 之 持续集成建设---自主研发(总括)
  8. 【ManageEngine卓豪】网络运维管理是什么,网络运维平台有什么用
  9. C语言——喝汽水,1瓶汽水1元,2个空瓶可以换一瓶汽水, 给20元,可以多少汽水
  10. Forecast2013中国电子商务蓝皮书-DCCI简版