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. 换个语言学一下 Golang (3)——数据类型

    在 Go 编程语言中,数据类型用于声明函数和变量. 数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存. Go 语言按类别有以下几种 ...

  2. CMDB数据库设计

    title: CMDB 数据库设计 tags: Django --- CMDB数据库设计 具体的资产 服务器表和网卡.内存.硬盘是一对多的关系,一个服务器可以有多个网卡.多个内存.多个硬盘 hostn ...

  3. stm32F042 (二) 按键触发中断

    已经实现GPIO口输出高低电平控制LED,这里实现按键触发中断来改变LED闪亮的频率,因为PB3连着LED,所以PB3的输出模式没有改变,随意选一个GPIO口PA7接按键产生中断.因为nucleo开发 ...

  4. Python——函数入门(一)

    一.理解函数 举一个例子,当我们需要重复使用一个功能的时候,不可能每次都去复制一次代码,这个时候就需要用到函数了,所谓的函数,简单来说就是给函数取一个名字,当需要用到这个功能的时候,就可以通过这个名字 ...

  5. 沙盒(SandBox)

    iOS 应用沙盒机制就是指 iOS 应用程序只能在为该程序创建的文件系统中读取文件,不可以去其它地方访问,此区域被成为沙盒,所以所有的非代码文件都要保存在此,例如图像,图标,声音,映像,属性列表,文本 ...

  6. ajax $.post 一直报 Forbidden (CSRF token missing or incorrect.)

    由于后台整合类视图代码,所以修改了写法,完了之后用下面的写法写的post请求都报 403 error $.post( "{% url 'test_record:select_node_pag ...

  7. python入门:最基本的用户登录

    #! usr/bin/env python # -*- coding: utf-8 -*- #最基本的用户登录 import getpass usre = input("username:& ...

  8. jQuery获取动态添加的元素,live和on的区别

    今天给大家说一下如果用jQuery获取动态添加的元素,通常如果你在网页上利用jQuery添加一个元素,那么用平常的jQuery获取元素的方法无效的获取不到的.可以用以下的方法获取动态元素!假设我们现在 ...

  9. 使用nohup+& 踩到的坑

    首先分清楚nohup与&: &是指在后台运行一般在执行命令后,都会显式的在前台执行,当Ctrl+C后进程回宕掉,但是 在命令后加&,即使Ctrl+C,程序还在进行,但是,当关闭 ...

  10. leetcode-14-basic-breadthFirstSearch

    BFS: breadth first search 107. Binary Tree Level Order Traversal II 解题思路: 本来我是用map<int,int>存所有 ...