HDU 3966 & POJ 3237 & HYSBZ 2243 & HRBUST 2064 树链剖分
树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询
思想是将一棵树分成不想交的几条链 并且由于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 long vector<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 long const 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") ;
}
}
}
}
HDU 3966 & POJ 3237 & HYSBZ 2243 & HRBUST 2064 树链剖分的更多相关文章
- HDU 3966 & POJ 3237 & HYSBZ 2243 树链剖分
树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...
- HDU 3966 Aragorn's Story(模板题)【树链剖分】+【线段树】
<题目链接> 题目大意: 给定一颗带点权的树,进行两种操作,一是给定树上一段路径,对其上每个点的点权增加或者减少一个数,二是对某个编号点的点权进行查询. 解题分析: 树链剖分的模板题,还不 ...
- POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )
POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...
- bzoj-2243 2243: [SDOI2011]染色(树链剖分)
题目链接: 2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6267 Solved: 2291 Descript ...
- BZOJ 2243: [SDOI2011]染色 [树链剖分]
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6651 Solved: 2432[Submit][Status ...
- POJ 2763:Housewife Wind(树链剖分)
http://poj.org/problem?id=2763 题意:给出 n 个点, n-1 条带权边, 询问是询问 s 到 v 的权值, 修改是修改存储时候的第 i 条边的权值. 思路:树链剖分之修 ...
- BZOJ 2243: [SDOI2011]染色 (树链剖分+线段树合并)
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243 树链剖分的点剖分+线段树.漏了一个小地方,调了一下午...... 还是要细心啊! 结 ...
- Bzoj 2243: [SDOI2011]染色 树链剖分,LCT,动态树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 5020 Solved: 1872[Submit][Status ...
- 2243: [SDOI2011]染色 树链剖分+线段树染色
给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段), 如“112221”由3段组 ...
随机推荐
- Python 基础函数
函数: 在程序设计中,函数是指用于进行某种计算的一系列语句的有名称的组合. 定义一个函数时,需要指定函数的名称并写下一系列程序语句.定义时不会执行,运行代码时,先加载进内存中,之后使用名称来调用这个函 ...
- [Spring Data Repositories]学习笔记--使用现有的repository
以下内容是在学习Spring-Data-mongoDB中的Spring Data Repositories时做的一些笔记.备忘! 感觉学习还是看官方的资料比较透彻一些. Spring Data Rep ...
- FZU2030(括号匹配)
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=110977#problem/E 题目大意:略 题目思路:数据范围很小,可以搜索, ...
- java 多种判断key是否在map中存在的方法
java 中有时候会遇到判断传过来的map里是否包含了指定的key,我目前只发现两种办法,如果有其他方法欢迎补充 我添加上去: HashMap map = new HashMap(); map.put ...
- HUST 1354 - Rubiks (DP)
1354 - Rubiks 时间限制:1秒 内存限制:64兆 452 次提交 102 次通过 题目描述 Isun is a genius. Not only he is an expert in al ...
- Intellij IDEA工具的常用快捷键
掌握如下常用快捷键可以使自己的开发效率提供十倍. ctrl + B : 转到类或者方法的定义 ctrl + Alt + B:弹出接口/虚类的实现类/子类 ctrl + Alt + 左箭头/右箭头 : ...
- 【python】-- Django
Django Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Sessio ...
- linux 安装zip/unzip/g++/gdb/vi/vim等软件
近期公司新配置了一台64位云server.去部署的时候发现,没有安装zip/unzip压缩解压软件. 于是仅仅好自己安装这两个软件.linux最好用的还是yum. 两个指令就安装好了. 首先把软件安装 ...
- Insert Buffering
14.5.13.4 Insert Buffering Database applications often insert new rows in the ascending order of the ...
- 字符串之strstr
功能:查找第二个字符串是否存在第一个字符串中. 输入:字符串1,字符串2 返回值:成功返回str1中的位置,失败返回NULL #include <iostream> using names ...