Qtree Ⅰ

题意:https://vjudge.net/problem/SPOJ-QTREE

   带修路径查询最大边权

sol :树链剖分,之后每条重链就是一个连续的区间,拿线段树维护即可

    简单讲讲链剖吧.....就是把树边划分为轻重边,重边的定义是和siz最大的儿子之间的边

    通过两次dfs实现,可以证明重链(重边形成的链)不超过logn条

    直接上代码吧,复杂度O(nlogn^2)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int Mx=;
struct Edge { int x,y,val; } edge[Mx];
struct Tree { int l,r,val; } tree[*Mx];
int n,cnt,dep[Mx],siz[Mx],fa[Mx],num[Mx],son[Mx],top[Mx];//top表示最近的重链父节点
int tot,nxt[*Mx],head[Mx],ver[*Mx],val[*Mx];
void clear()
{
memset(head,,sizeof(head));
memset(son,,sizeof(son));
cnt=;tot=;
}
inline void add(int x,int y,int z)
{
tot++;
nxt[tot]=head[x];
ver[tot]=y;
val[tot]=z;
head[x]=tot;
}
//链剖
void dfs1(int u,int Fa,int Dep)
{
dep[u]=Dep,siz[u]=,son[u]=,fa[u]=Fa;
for(int i=head[u];i;i=nxt[i])
{
int v=ver[i];
if(v==Fa) continue;
dfs1(v,u,Dep+);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v]) son[u]=v;
}
}
void dfs2(int u,int Top)
{
top[u]=Top,num[u]=++cnt;
if(son[u]) dfs2(son[u],Top);
for(int i=head[u];i;i=nxt[i])
{
int v=ver[i];
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
}
//线段树
void pushup(int x) { tree[x].val=max(tree[x<<].val,tree[x<<|].val); }
void build(int l,int r,int v)
{
tree[v].l=l;tree[v].r=r;
if(l==r) { tree[v].val=val[l]; return ; }
int mid=(l+r)>>;
build(l,mid,v*); build(mid+,r,v*+);
pushup(v);
}
void update(int u,int v,int val)
{
if(tree[u].l==tree[u].r) { tree[u].val=val; return ; }
int mid=(tree[u].l+tree[u].r)/;
if(v<=mid) update(u*,v,val);
else update(u*+,v,val);
pushup(u);
}
int query(int x,int l, int r)
{
if(tree[x].l>=l&&tree[x].r<=r) return tree[x].val;
int ans=,mid=(tree[x].l+tree[x].r)/;
if(l<=mid) ans=max(ans,query(x<<,l,r));
if(r>mid) ans=max(ans,query(x<<|,l,r));
return ans;
}
int solve(int u,int v)
{
int ans=,Top1=top[u],Top2=top[v];
while(Top1!=Top2)
{
if(dep[Top1]<dep[Top2]) swap(Top1,Top2),swap(u,v);
ans=max(ans,query(,num[Top1],num[u]));
u=fa[Top1];Top1=top[u];
}
if(u==v) return ans;
if(dep[u]>dep[v]) swap(u,v);
ans=max(ans,query(,num[son[u]],num[v]));
return ans;
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
clear();
scanf("%d",&n);
for(int i=,x,y,z;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
edge[i].x=x;edge[i].y=y;edge[i].val=z;
add(x,y,z);add(y,x,z);
}
dfs1(,,);dfs2(,);
for(int i=;i<n;i++)
{
if(dep[edge[i].x]<dep[edge[i].y]) swap(edge[i].x,edge[i].y);
val[num[edge[i].x]]=edge[i].val;
}
build(,cnt,);
while()
{
char s[];scanf("%s",s);if(s[]=='D') break;
int x,y; scanf("%d%d",&x,&y);
if(s[]=='Q') printf("%d\n",solve(x,y));
if (s[]=='C') update(,num[edge[x].x],y);
}
}
return ;
}

Qtree Ⅱ

题意:https://vjudge.net/problem/SPOJ-QTREE2

   路径查询距离、第K个点

sol :本来想都没想直接写了个链剖,结果发现不用QAQ

   这应该是Qtree1~7里最水的吧QAQ,直接倍增就行了

   预处理每个点到根的路径长度,第一问求出lca后直接输出dis[x]+dis[y]-2dis[lca]即可

   第二问需要考虑是在x-lca的路径上还是y-lca的路径上,然后直接倍增求第k个祖先即可

   P.S.这里可以扩展一下,广义的树上倍增,orz集训队dalao

     可以有O(D * N ^ ((D+1)/D))的时间的预处理。
     设K=N^(1/D),预处理出所有点分别的第i*K^j个祖先(对于所有1<=i<K且0<=j<D)。
     然后每次求时将要跳的步数转化成一个不超过D位的K进制数就可以在O(D)的时间内求出来啦。
     我们平时在说的倍增(预处理出每个点的第1,2,4,8,16,...个祖先)是D=log2(N),K=2的特例。
     D的值可以根据需要调整。

   话说,我一开始还wa了半天,结果发现是return 0打到了while(T--)里面QAQ

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int Mx=;
int n,len,tmp,fa[Mx],fa1[Mx][],dep[Mx],val[Mx];
int tot,head[Mx],nxt[*Mx],ver[*Mx],val1[*Mx];
void clear()
{
tot=;
memset(head,,sizeof(head));
memset(val,,sizeof(val));
memset(fa1,,sizeof(fa1));
}
inline void add(int x,int y,int z)
{
tot++;
nxt[tot]=head[x];
ver[tot]=y;
val1[tot]=z;
head[x]=tot;
}
void dfs(int u,int Fa,int Val,int Dep)
{
dep[u]=Dep,fa[u]=Fa,val[u]=val[Fa]+Val;
for(int i=head[u];i;i=nxt[i])
{
int v=ver[i];
if(v==Fa) continue;
dfs(v,u,val1[i],Dep+);
}
}
void pre()
{
for(int i=;i<=n;i++) fa1[i][]=fa[i];
for(int j=;<<j<=n;j++)
for(int i=;i<=n;i++)
fa1[i][j]=fa1[fa1[i][j-]][j-];
}
int find_lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(tmp=,len=;(<<tmp)<=dep[x];tmp++); tmp-=;
for(int j=tmp;j>=;j--)
if(dep[x]-(<<j)>=dep[y]) x=fa1[x][j];
if(x==y) return x;
for(int j=tmp;j>=;j--)
if(fa1[x][j]!=-&&fa1[x][j]!=fa1[y][j])
x=fa1[x][j],y=fa1[y][j];
return fa1[x][];
}
int find_fa(int x,int k)
{
int Dep=dep[x]-k+;
for(tmp=;(<<tmp)<=dep[x];tmp++); tmp--;
for(int j=tmp;j>=;j--)
{
if(dep[x]==Dep) break;
if(dep[fa1[x][j]]>=Dep) x=fa1[x][j];
}
return x;
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
clear(); scanf("%d",&n);
for(int i=,x,y,z;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);add(y,x,z);
}
fa[]=;dfs(,,,);pre();
while()
{
char ch[];scanf("%s",ch);
if(ch[]=='O') break;
if(ch[]=='D')
{
int x,y,lca; scanf("%d%d",&x,&y);
lca=find_lca(x,y);
printf("%d\n",val[x]+val[y]-(*val[lca]));
}
else
{
int x,y,k,lca;scanf("%d%d%d",&x,&y,&k);
lca=find_lca(x,y);
if(dep[x]-dep[lca]+>k) printf("%d\n",find_fa(x,k));
else printf("%d\n",find_fa(y,dep[y]+dep[x]-(*dep[lca])+-k));
}
}
}
return ;
}

Qtree Ⅲ

题意:https://vjudge.net/problem/CodeChef-QTREE

   给一棵树,黑白染色,有两个操作:单点颜色修改、查询1~v的路径上最先出现黑点的位置

sol :显然LCT可做

Qtree的更多相关文章

  1. 激!QTREE系列

    我现在才开始刷 QTREE 是不是太弱了?算了不管他…… QTREE: 树链剖分裸题(据说 lct 会超时……该说是真不愧有 spoj 的气息吗?) #include <cstdio> # ...

  2. QTREE系列题解

    打了快一星期的qtree终于打完了- - (其实还有两题改不出来弃疗了QAQ) orz神AK一星期前就虐完QTREE 避免忘记还是简单写下题解吧0 0 QTREE1 题意: 给出一颗带边权树 一个操作 ...

  3. QTREE 树链剖分---模板 spoj QTREE

    <树链剖分及其应用> 一文讲得非常清楚,我一早上就把他学会了并且A了这题的入门题. spoj QTREE 题目: 给出一棵树,有两种操作: 1.修改一条边的边权. 2.询问节点a到b的最大 ...

  4. Cogs 1672. [SPOJ375 QTREE]难存的情缘 LCT,树链剖分,填坑计划

    题目:http://cojs.tk/cogs/problem/problem.php?pid=1672 1672. [SPOJ375 QTREE]难存的情缘 ★★★☆   输入文件:qtree.in  ...

  5. SPOJ QTREE 系列解题报告

    题目一 : SPOJ 375 Query On a Tree http://www.spoj.com/problems/QTREE/ 给一个树,求a,b路径上最大边权,或者修改a,b边权为t. #in ...

  6. QTREE - Query on a tree

    QTREE - Query on a tree 题目链接:http://www.spoj.com/problems/QTREE/ 参考博客:http://blog.sina.com.cn/s/blog ...

  7. 树链剖分-SPOJ375(QTREE)

    QTREE - Query on a tree You are given a tree (an acyclic undirected connected graph) with N nodes, a ...

  8. spoj QTREE - Query on a tree(树链剖分+线段树单点更新,区间查询)

    传送门:Problem QTREE https://www.cnblogs.com/violet-acmer/p/9711441.html 题解: 树链剖分的模板题,看代码比看文字解析理解来的快~~~ ...

  9. SPOJ QTREE Query on a tree 树链剖分+线段树

    题目链接:http://www.spoj.com/problems/QTREE/en/ QTREE - Query on a tree #tree You are given a tree (an a ...

  10. SPOJ QTREE

    QTREE /* 题目大意:维护一棵树,允许修改边权以及查询链上最大值 题解:我们将边权转为点权,标记在深度较深的点上,树链剖分后用线段树处理即可 */ #include <cstdio> ...

随机推荐

  1. UVA 1619 Feel Good 感觉不错 (扫描法)

    Feel Good Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Bill is deve ...

  2. Processing一些常用技巧

    一些常用技巧总结: Tweak模式 快速查找函数用法 显示与输入中文注释 代码快速对齐 批量添加注释符 Tweak模式 Tweak模式是非常有用的功能,自3.0版本后,它就正式整合到Processin ...

  3. for...in、for...of、forEach()有什么区别

    本文原链接:https://cloud.tencent.com/developer/article/1360074 for of 和 for in 循环 循环遍历数组的时候,你还在用 for 语句走天 ...

  4. vue axios 请求 https 的特殊处理

    最近遇到自签发的CA证书,在前端axios请求https请求时,无法自动加载证书. 解决方法:将无法加载的请求在浏览器新窗口手动加载,选择继续连接. 重新加载,问题解决. 根本原因:因为自签发证书,浏 ...

  5. OO作业第三单元总结

    目录 一.JML语言理论基础及应用工具链 二.部署JMLUnitNG,自动生成测试用例 三.架构设计 第一次作业 第二次作业 第三次作业 四.Bug分析 五.心得体会 一.JML语言理论基础及应用工具 ...

  6. C07 模块化开发信息管理系统案例

    目录 需求分析 问题分析 开发阶段 需求分析 总体需求 学员信息管理系统支持以下功能 增加学员信息功能 删除学员信息功能 查询学员信息功能 修改学员信息功能 输出所有学员信息功能 退出系统 其他需求 ...

  7. CentOS7 中使用 firewall-cmd 控制端口和端口转发

    0X00 firewalld 守护进程 firewall-cmd命令需要firewalld进程处于运行状态.我们可以使用systemctl status/start/stop/restart fire ...

  8. Virt-install用法:

       #一般选项:指定虚拟机的名称.内存大小.VCPU个数及特性等 -n  NAME,  --name=NAME:虚拟机名称,需全局惟一: -r  MEMORY,  --ram=MEMORY:虚拟机内 ...

  9. pandas删除及其映射修改操作。

    1.使用drop_duplicates()函数删除重复的行 df.drop_duplicates() 2.映射 映射的含义,创建一个映射关系,把values元素和一个特定的标签或字符串绑定 map = ...

  10. js cookie 操作

    <html> <head> <meta charset="utf-8"> <title>Javascript cookie</ ...