传送门:Problem QTREE

https://www.cnblogs.com/violet-acmer/p/9711441.html

题意:

    You are given a tree (an acyclic undirected connected graph,无向无环连通图) with N nodes,
and edges numbered 1, 2, 3...N-1.
We will ask you to perform some instructions of the following form:
有两个操作
CHANGE i ti : change the cost of the i-th edge to ti(第i条边的权值变为ti)
or
QUERY a b : ask for the maximum edge cost on the path from node a to node b
(查询节点a,b间路径的最大权值)

题解:

  树链剖分模板题,看代码理解的更快;

AC代码献上:

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define ls(x) ((x)<<1)
#define rs(x) ((x)<<1 | 1)
const int maxn=; //===========链式前向星===============
struct Node1
{
int to;
int next;
}edge[*maxn];
int head[maxn];
int cnt;
void addEdge(int u,int v)
{
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
//====================================
//=========树链剖分用到的变量=========
int fa[maxn];//fa[u] : 节点u的父节点
int newId[maxn];//newId[u] : u与其父亲节点的连边在线段树中的位置
int depth[maxn];//depth[u] : 节点u的深度
int siz[maxn];//siz[u] : 以u为根的子树的节点数
int top[maxn];//top[u] : 节点u所在的重链的顶端节点
int son[maxn];//son[u] : 节点u重儿子
int label;//记录newId[]中新边对应的编号
//====================================
//==========两次DFS()================
void dfs1(int u,int f,int d) //第一遍dfs求出fa[],depth[],siz[],son[]
{
depth[u]=d;
fa[u]=f;
siz[u]=;
for(int i=head[u];~i;i=edge[i].next)
{
int to=edge[i].to;
if(to != f)
{
dfs1(to,u,d+);
siz[u] += siz[to];
if(son[u] == - || siz[to] > siz[son[u]])
son[u] = to;
}
}
}
void dfs2(int u,int sp) //第二遍dfs求出top[]和newId[]
{
top[u]=sp;
newId[u]=++label;
if(son[u] == -)
return ;
dfs2(son[u],sp); for(int i=head[u];~i;i=edge[i].next)
{
int to=edge[i].to;
if(to != son[u] && to != fa[u])
dfs2(to,to);
}
}
//===================================
//=============线段树================
struct Node2
{
int l,r;
int Max;
int mid()
{
return l+((r-l)>>);
}
}segTree[maxn*];
void buildTree(int l,int r,int pos)
{
segTree[pos].l = l,segTree[pos].r = r;
segTree[pos].Max = ;
if(l == r)
return; int mid = (l+r)/;
buildTree(l,mid,ls(pos));
buildTree(mid+,r,rs(pos));
}
void push_up(int k)//向上更新
{
segTree[k].Max = max(segTree[ls(k)].Max,segTree[rs(k)].Max);
}
void update(int k,int val,int pos) //单点更新
{
if(segTree[pos].l == segTree[pos].r)
{
segTree[pos].Max = val;
return;
} int mid=segTree[pos].mid(); if(k <= mid)
update(k,val,ls(pos));
else
update(k,val,rs(pos));
push_up(pos);
}
int query(int l,int r,int pos)//查询线段树中[l,r]的最大值
{
if(segTree[pos].l == l && segTree[pos].r == r)
return segTree[pos].Max; int mid=segTree[pos].mid(); if(r <= mid)
return query(l,r,ls(pos));
else if(l > mid)
return query(l,r,rs(pos));
else
return max(query(l,mid,ls(pos)),query(mid+,r,rs(pos)));
}
int Find(int u,int v)//查询u->v边的最大值
{
int res=;
while(top[u] != top[v])
{
if(depth[top[u]] > depth[top[v]])
{
res=max(res,query(newId[top[u]],newId[u],));
u=fa[top[u]];
}
else
{
res=max(res,query(newId[top[v]],newId[v],));
v=fa[top[v]];
}
}
if(u == v)
return res;
if(depth[u] > depth[v])
swap(u,v);
return max(res,query(newId[son[u]],newId[v],));
}
//===================================
void Init()
{
cnt=;
memset(head,-,sizeof(head));
label=;
memset(son,-,sizeof(son));
}
int e[maxn][];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
Init();
scanf("%d",&n);
for(int i=;i < n;++i)
{
scanf("%d%d%d",&e[i][],&e[i][],&e[i][]);
addEdge(e[i][],e[i][]);
addEdge(e[i][],e[i][]);
}
dfs1(,,);
dfs2(,);
buildTree(,label,);
for(int i=;i < n;++i)
{
if(depth[e[i][]] > depth[e[i][]])
swap(e[i][],e[i][]);//确保 e[i][0] 为 e[i][1]的父节点
update(newId[e[i][]],e[i][],);//更新e[i][1]与其父节点e[i][0]的连边在线段树中的位置
}
char op[];
while(scanf("%s",op) && op[] != 'D')
{
int u,v;
scanf("%d%d",&u,&v);
if(op[] == 'Q')
printf("%d\n",Find(u,v));
else
update(newId[e[u][]],v,);
}
}
}

分割线:2019.5.10

省赛倒计时2天;

熟悉一下树链剖分,改改代码风格:

 #include<bits/stdc++.h>
using namespace std;
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=1e4+; int n;///n个节点
int e[maxn][];///节点e[i][0]与节点e[i][1]有条权值为e[i][2]的边
int num;
int head[maxn];
struct Edge
{
int to;
int next;
}G[maxn<<];
void addEdge(int u,int v)
{
G[num]=Edge{v,head[u]};
head[u]=num++;
}
int fa[maxn];///fa[u]:节点u的父节点
int tid[maxn];///tid[u]:节点u在线段树中的新编号
int rid[maxn];///tid[u]=cnt,rid[cnt]=u,通过线段树中的编号查找节点
int dep[maxn];///节点的深度
int siz[maxn];///siz[u]:以u为根的子树的节点数
int son[maxn];///son[u]:节点u重儿子
int top[maxn];///top[u]:节点u所在重链的顶端节点
struct Seg
{
int l,r;
int maxVal;///区间维护最大值,根据题意而定
int mid(){return l+((r-l)>>);}
int len(){return r-l+;}
}seg[maxn<<];
void pushUp(int pos)
{
seg[pos].maxVal=max(seg[ls(pos)].maxVal,seg[rs(pos)].maxVal);
}
void buildSegTree(int l,int r,int pos)
{
seg[pos].l=l;
seg[pos].r=r;
seg[pos].maxVal=;
if(l == r)
return ;
int mid=l+((r-l)>>);
buildSegTree(l,mid,ls(pos));
buildSegTree(mid+,r,rs(pos));
}
void Update(int l,int val,int pos)///单点更新
{
if(seg[pos].l == seg[pos].r)
{
seg[pos].maxVal=val;
return ;
}
int mid=seg[pos].mid();
if(l <= mid)
Update(l,val,ls(pos));
else
Update(l,val,rs(pos));
pushUp(pos);
}
int Query(int l,int r,int pos)///区间查询
{
if(seg[pos].l == l && seg[pos].r == r)
return seg[pos].maxVal;
int mid=seg[pos].mid();
if(r <= mid)
return Query(l,r,ls(pos));
else if(l > mid)
return Query(l,r,rs(pos));
else
return max(Query(l,mid,ls(pos)),Query(mid+,r,rs(pos)));
}
int Find(int u,int v)
{
int topU=top[u];
int topV=top[v];
int ans=;
while(topU != topV)///u,v不在一条重链上
{
if(dep[topU] > dep[topV])///人为规定topU的深度低
{
swap(topU,topV);
swap(u,v);
}
ans=max(ans,Query(tid[topV],tid[v],));
v=fa[topV];///v来到topV的父节点所在的重链
topV=top[v];
}
if(u == v)
return ans; if(dep[u] > dep[v])
swap(u,v);
return max(ans,Query(tid[son[u]],tid[v],));
}
void DFS1(int u,int f,int depth)///第一遍DFS求出fa,dep,siz,son
{
fa[u]=f;
siz[u]=;
dep[u]=depth;
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if(v == f)///此处是v == f才continue,在这儿出过错
continue;
DFS1(v,u,depth+);
siz[u] += siz[v];
if(son[u] == - || siz[v] > siz[son[u]])///更新重儿子
son[u]=v;
}
}
void DFS2(int u,int anc,int &k)///第二遍DFS求出tid,rid,top
{
top[u]=anc;
tid[u]=++k;
rid[k]=u;
if(son[u] == -)
return ;
DFS2(son[u],anc,k); for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if(v != son[u] && v != fa[u])
DFS2(v,v,k);
}
}
void Solve()
{
DFS1(,,);
int k=;
DFS2(,,k);
buildSegTree(,k,);///[1,k]重新编号的节点建树 for(int i=;i < n;++i)
{
///将e[i][0]与e[i][1]的边权存入儿子节点e[i][1]中
if(dep[e[i][]] > dep[e[i][]])
swap(e[i][],e[i][]);
///更新e[i][1]与其父节点e[i][0]的连边在线段树中的位置
Update(tid[e[i][]],e[i][],);
}
char order[];
while(~scanf("%s",order) && order[] != 'D')
{
int u,v;
scanf("%d%d",&u,&v);
if(order[] == 'Q')
printf("%d\n",Find(u,v));///查询节点u,v间路径的最大值
else///更新第u条边的权值,变为v,第u条边的权值信息记录在了tid[e[u][1]]中
Update(tid[e[u][]],v,);
}
} void Init()///初始化head,num,son
{
num=;
mem(head,-);
mem(son,-);
}
int main()
{
int test;
while(~scanf("%d",&test))
{
while(test--)
{
Init();///多组输入test,Init()放在while(test--)内
scanf("%d",&n);
for(int i=;i < n;++i)///n-1条边
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
e[i][]=u;
e[i][]=v;
e[i][]=w;
addEdge(u,v);
addEdge(v,u);
}
Solve();
}
}
return ;
}

spoj QTREE - Query on a tree(树链剖分+线段树单点更新,区间查询)的更多相关文章

  1. Spoj Query on a tree SPOJ - QTREE(树链剖分+线段树)

    You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...

  2. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

  3. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

  4. POJ3237 Tree 树链剖分 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ3237 题意概括 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1 ...

  5. 【CF725G】Messages on a Tree 树链剖分+线段树

    [CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息 ...

  6. Water Tree CodeForces 343D 树链剖分+线段树

    Water Tree CodeForces 343D 树链剖分+线段树 题意 给定一棵n个n-1条边的树,起初所有节点权值为0. 然后m个操作, 1 x:把x为根的子树的点的权值修改为1: 2 x:把 ...

  7. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  8. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  9. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  10. Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组

    Aragorn's Story 来源:http://www.fjutacm.com/Problem.jsp?pid=2710来源:http://acm.hdu.edu.cn/showproblem.p ...

随机推荐

  1. Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final)-D- Array Restoration

    我们知道不满足的肯定是两边大中间小的,这样就用RMQ查询两个相同等值的区间内部最小值即可,注意边界条件 #include<bits/stdc++.h> #define x first #d ...

  2. CentOS 网卡自动启动、配置等ifcfg-eth0教程

    装完centos后发现网卡没有自动启动, vi /etc/sysconfig/network-scripts/ifcfg-eth0 将ONBOOT=no 改为yes即可 原文链接: http://yp ...

  3. M1阶段个人总结

    经过4周的开发,我们团队的第一阶段已经结束了. 这一个月来我由于其他事情较多,所以开发的工作主要交给了另外的三名同学. 我主要负责制定代码规范和工程结构,通过github来跟进项目进度,提供一些技术支 ...

  4. <编写有效用例>读书笔记3

    <编写有效用例>读书笔记3 第三部分主要内容是对忙于编写用例的人的提示第20章:对每个用例的提示1.每个用例都是一篇散文:这个提示提醒我们将注意力集中与文字而不是图画上,同时帮助了解将要遇 ...

  5. SQL 别名

    Sql中添加别名有三种方式:

  6. 定义类型别名(typedef,using)

    说到类型别名,无非是给类型名(如int,char,float,double,bool)取一个比较有特殊含义的名字而已 最常用的关键莫过于 typedef 吧 typedef最常见的用法是与结构体str ...

  7. mysql复杂查询

    所谓复杂查询,指涉及多个表.具有嵌套等复杂结构的查询.这里简要介绍典型的几种复杂查询格式. 一.连接查询 连接是区别关系与非关系系统的最重要的标志.通过连接运算符可以实现多个表查询.连接查询主要包括内 ...

  8. [书摘]HTTPS--From图解HTTP

    1.  HTTP存在的安全性风险: 1) 通信过程使用明文,容易被窃听 2) 不验证通信方的身份,可能遭遇伪装 3) 不验证通信数据包的完整性,可能遭遇篡改 2. HTTP+加密+认证+完整性保护=H ...

  9. MES模块

    基础数据管理:产品模型.工厂模型.工艺模型 仓储管理 成本管理 绩效管理 看板管理 日志管理 设备管理:工装管理.设计器具管理.设备保养管理.设备备件管理.设备采集管理.设备点检管理.设备故障管理.设 ...

  10. YII2十三大特性

    第一(框架&项目) 1. 框架安装 2. 框架扩展安装 3. 项目初始化-->php yii init 4. 美化URL配置 'urlManager' => [ 'enablePr ...