spoj QTREE - Query on a tree(树链剖分+线段树单点更新,区间查询)
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(树链剖分+线段树单点更新,区间查询)的更多相关文章
- 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, ...
 - 【POJ3237】Tree(树链剖分+线段树)
		
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
 - 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 ...
 - POJ3237 Tree 树链剖分 线段树
		
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ3237 题意概括 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1 ...
 - 【CF725G】Messages on a Tree 树链剖分+线段树
		
[CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息 ...
 - Water Tree CodeForces 343D 树链剖分+线段树
		
Water Tree CodeForces 343D 树链剖分+线段树 题意 给定一棵n个n-1条边的树,起初所有节点权值为0. 然后m个操作, 1 x:把x为根的子树的点的权值修改为1: 2 x:把 ...
 - 【BZOJ-2325】道馆之战      树链剖分 + 线段树
		
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
 - POJ3237 (树链剖分+线段树)
		
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
 - BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
		
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
 - Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组
		
Aragorn's Story 来源:http://www.fjutacm.com/Problem.jsp?pid=2710来源:http://acm.hdu.edu.cn/showproblem.p ...
 
随机推荐
- Git版本控制器使用总结性梳理
			
Git为何物?Git 是什么?大家肯定会说不就是版本控制器嘛,是的Git是目前世界上最先进的分布式版本控制系统(没有之一).1)那什么是版本控制器?举个简单的例子,比如我们用Word写文章,那你一定有 ...
 - C. Oh Those Palindromes
			
题意 给以一个字符串,让你重排列,使得回文子串的数目最多 分析 对于一个回文串,在其中加入一些字符并不会使回文子串的个数增加,所以对于相同的字符一起输出即可,我是直接排序 代码 #include< ...
 - Linux内核分析 笔记八 进程的切换和系统的一般执行过程   ——by王玥
			
一.进程切换的关键代码switch_to的分析 (一)进程调度与进程调度的时机分析 1.不同类型的进程有不同的调度需求 第一种分类: I/O-bound:频繁地进行I/O,花费很多的时间等待I/O操作 ...
 - “数学口袋精灵”App的第三个Sprint计划(总结与团队感悟)----开发日记
			
第三阶段Sprint完成情况: 我们的"数学口袋精灵"App已经完成了,该app能随机产生多种形式的算式,比如带括号的,分数四则运算,混合运算,阶乘等,通过游戏形式让用户乐在其中. ...
 - maven私服    Nexus2.x.x私服安装配置
			
一.Nexus的下载和安装 1.下载nexus ,下载地址:https://www.sonatype.com/download-oss-sonatype 2.打开目录nexus-2.x.x-xx-b ...
 - PAT 1038 统计同成绩学生
			
https://pintia.cn/problem-sets/994805260223102976/problems/994805284092887040 本题要求读入N名学生的成绩,将获得某一给定分 ...
 - PowerShell一例
			
(Get-WmiObject -query ‘select * from SoftwareLicensingService’).OA3xOriginalProductKey
 - wamp升级php5.3.10到5.4.31版本
			
wamp升级php5.3.10到5.4.31版本 1. 停止WAMP服务器. 2. 去网站windows.php.net 下载php-5.4.31-nts-Win32-VC9-x86.zip. 不 ...
 - linux_shell自定义命令
			
一.命令可执行文件所在目录 shell命令可执行文件所在目录是保存在环境变量PATH中的,终端输入如下命令查看 PATH 环境变量的内容: $ echo $PATH 我的linux输出如下: /opt ...
 - webstrom 安装Babel
			
https://www.jianshu.com/p/b9bd2ec9ec80 https://www.cnblogs.com/zhishaofei/p/6061568.html https://blo ...