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 ...
随机推荐
- Centos6.9下安装并使用VNC的操作记录
VNC是一个的"远程桌面"工具.,通常用于“图形界面”的方式登录服务器,可视化操作.废话不多说了,操作记录如下: 1)安装桌面环境 [root@vm01 ~]# yum -y gr ...
- B. Divisor Subtraction
链接 [http://codeforces.com/contest/1076/problem/B] 题意 给你一个小于1e10的n,进行下面的运算,n==0 结束,否则n-最小质因子,问你进行多少步 ...
- Visual Studio2013安装过程以及单元测试
一.安装环境 操作系统版本:Windows10家庭中文版64位 CPU:i5-4200u 1.60GHz 硬盘内存:750G 二.安装版本 Visual Studio2013 三.安装过程 Visu ...
- 个人阅读作业WEEK7 (软件工程的瀑布, 大泥球, 教堂,集市,和银弹)
一 . 关于银弹 (Silver Bullet) 银弹,被引申为解决问题的有效办法.IBM大型机之父福瑞德·布鲁克斯在1986年的论文<没有银弹>中表达了他的观点:软件工程中不存在银弹—— ...
- 2017-2018-2 1723《程序设计与数据结构》第九周作业 & 第二周结对编程 总结
作业地址 第九次作业:https://edu.cnblogs.com/campus/besti/CS-IMIS-1723/homework/1878 (作业界面已评分,可随时查看,如果对自己的评分有意 ...
- 手工编程:hello world
全部用命令行工具和Notepad编辑器,用手工创建并编译一个C的命令行程序:hello world. public class Hello{ public static void ma ...
- 现代程序设计 homework-02
首先显示博客要求: 描述在这么多相似的需求面前, 你怎么维护你的设计 (父类/子类/基类, UML, 设计模式, 或者其它方法) 让整个程序的架构不至于崩溃的? 建议从后往前来搞,比如我通读一遍需求 ...
- [转帖]以Windows服务方式运行ASP.NET Core程序
以Windows服务方式运行ASP.NET Core程序 原作者blog: https://www.cnblogs.com/guogangj/p/9198031.htmlaspnet的blog 需要持 ...
- Fantacy团队周一站立会议
词频分析模型 1.首先这次站会是周一开的,但是由于我个人的疏忽,没有落实到博客上,请见谅,连累了组长. 2.会议时间:2016年3月28日12:00~12:30. 持续时长:30分钟 会议参加成员:组 ...
- 软件工程_2nd weeks
本周上课没有板书,都由老师口头叙述 因此有的笔记记得不是很全,幸好有郑蕊师姐发布的课堂笔记,很好的梳理上课的内容~ 1.根据老师上课给的建议,进行了深刻的思考和反思 1.1 作为一个学硕研究生,这门课 ...