\[\texttt{Preface}
\]

这题在 \(\text{Luogu}\) 上竟然不能交 \(C++\) ,会一直 \(Waiting\) ,只能交非 \(C++\) 的语言。

所以打完了 \(C++\) 要转到 \(C\) 才能过。

要把什么 \(swap\) , \(max\) 各种函数换成手写,以及 \(C++\) 的特色(例如 using namespace std;inline )都要去掉。

详情见 \(Code\) 。

\[\texttt{Description}
\]

给出一个 \(n\) 个点的带权树,需要支持以下操作:

  • CHANGE i ti 将第 \(i\) 条边的权值改为 \(t_i\) 。
  • QUERY a b 询问 \(a\) 到 \(b\) 的路径上最大边权。

多组数据。

\[\texttt{Solution}
\]

从这个询问 " 查询路径信息,边带修 " 来说,我们可以知道这是一个树剖板子题。

不了解树剖的童鞋可以去了解一下,过一下 树剖模板

只不过这题不是一般的 " 点带修 " 而是 " 边带修 " ,也不要紧。

注意到除了根,每个节点都有父亲,那么我们可以把边的信息转化到点身上,每个节点的点权是它与它父亲所形成的边的边权。

例如 \(1\) 到 \(2\) 的一条长度为 \(3\) 的边(此时 \(1\) 是 \(2\) 的父亲),那么我们可以理解为 \(2\) 的点权是 \(3\) 。

这样就可以用树剖维护了。

但是令 \(z=\text{lca}(x,y)\) ,我们发现 \((fa[z],z)\) 这条边是不能被算进答案的。

在查询的最后一步,\(x\) 和 \(y\) 会在同一条重链上(设 \(dep_x<dep_y\)),此时 \(x\) 就是 \(z\) ,由于重链上的节点的 \(dfs\) 序是连续的,所以查询 \([dfn_x+1,dfn_y]\) 这段区间的最大值就可以避开计算 \(z\) 的信息了。

\[\texttt{Code}
\]

#include<stdio.h>

#define N 10100
#define M 20100 int read()
{
int x=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
return x*f;
} int tmp;
int max(int a,int b){return a>b?a:b;} int T; int n; struct Edge{
int u,v,w;
}e[N]; int tot,head[N],ver[M],edge[M],Next[M]; void add(int u,int v,int w)
{
ver[++tot]=v; edge[tot]=w; Next[tot]=head[u]; head[u]=tot;
} int val[N];
int d[N];
int fu[N];
int size[N];
int son[N]; void dfs1(int u)
{
size[u]=1;
for(int i=head[u];i;i=Next[i])
{
int v=ver[i],w=edge[i];
if(v==fu[u])continue;
fu[v]=u;
val[v]=w;
d[v]=d[u]+1;
dfs1(v);
size[u]+=size[v];
if(size[son[u]]<size[v])son[u]=v;
}
} int QwQ;
int dfn[N],idx[N];
int top[N]; void dfs2(int u)
{
QwQ++;
dfn[u]=QwQ,idx[QwQ]=u; if(son[u])
{
top[son[u]]=top[u];
dfs2(son[u]);
} for(int i=head[u];i;i=Next[i])
{
int v=ver[i];
if(v==fu[u]||v==son[u])continue;
top[v]=v;
dfs2(v);
}
} struct SegmentTree{
int l,r;
int max;
}t[N*4]; void upd(int p)
{
t[p].max=max(t[p*2].max,t[p*2+1].max);
} void build(int p,int l,int r)
{
t[p].l=l,t[p].r=r;
if(l==r)
{
t[p].max=val[idx[l]];
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
upd(p);
} void change(int p,int delta,int val)
{
if(t[p].l==t[p].r)
{
t[p].max=val;
return;
}
int mid=(t[p].l+t[p].r)/2;
if(delta<=mid)
change(p*2,delta,val);
else
change(p*2+1,delta,val);
upd(p);
} int ask(int p,int l,int r)
{
if(l<=t[p].l&&t[p].r<=r)return t[p].max;
int mid=(t[p].l+t[p].r)/2;
int val=0;
if(l<=mid)
val=max(val,ask(p*2,l,r));
if(mid<r)
val=max(val,ask(p*2+1,l,r));
return val;
} int path_ask(int u,int v)
{
int ans=0;
while(top[u]!=top[v])
{
if(d[top[u]]>d[top[v]])tmp=u,u=v,v=tmp;
ans=max(ans,ask(1,dfn[top[v]],dfn[v]));
v=fu[top[v]];
}
if(u==v)return ans;
if(d[u]>d[v])tmp=u,u=v,v=tmp;
ans=max(ans,ask(1,dfn[u]+1,dfn[v]));
return ans;
} void work()
{
tot=QwQ=0; for(int i=1;i<=n;i++)
head[i]=son[i]=0; n=read(); for(int i=1;i<n;i++)
{
e[i].u=read(),e[i].v=read(),e[i].w=read();
add(e[i].u,e[i].v,e[i].w),add(e[i].v,e[i].u,e[i].w);
} d[1]=1,top[1]=1;
dfs1(1),dfs2(1);
build(1,1,n); char opt[10];
while(scanf("%s",opt),opt[0]!='D')
{
int x=read(),y=read(); switch(opt[0])
{
case 'C':{ if(d[e[x].u]>d[e[x].v])
tmp=e[x].u,e[x].u=e[x].v,e[x].v=tmp; change(1,dfn[e[x].v],y); break;
} case 'Q':{ printf("%d\n",path_ask(x,y)); break;
}
}
}
} int main()
{
T=read(); while(T--) work(); return 0;
}

\[\texttt{Thanks} \ \texttt{for} \ \texttt{watching}
\]

题解 SP375 【QTREE - Query on a tree】的更多相关文章

  1. SP375 QTREE - Query on a tree (树剖)

    题目 SP375 QTREE - Query on a tree 解析 也就是个蓝题,因为比较长 树剖裸题(基本上),单点修改,链上查询. 顺便来说一下链上操作时如何将边上的操作转化为点上的操作: 可 ...

  2. SP375 QTREE - Query on a tree

    题意大意 给定\(n\)个点的树,边按输入顺序编号为\(1,2,...n-1\),要求作以下操作: CHANGE \(i\) \(t_i\) 将第\(i\)条边权值改为\(t_i\),QUERY \( ...

  3. QTREE - Query on a tree

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

  4. 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 ...

  5. SPOJ VJudge QTREE - Query on a tree

    Query on a tree Time Limit: 851MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu Submi ...

  6. SPOJ - QTREE Query on a tree题解

    题目大意: 一棵树,有边权,有两个操作:1.修改一条边的权值:2.询问两点间路径上的边的权值的最大值. 思路: 十分裸的树链剖分+线段树,无非是边权要放到深度大的一端的点上,但是有两个坑爹的地方,改了 ...

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

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

  8. SPOJ QTREE Query on a tree --树链剖分

    题意:给一棵树,每次更新某条边或者查询u->v路径上的边权最大值. 解法:做过上一题,这题就没太大问题了,以终点的标号作为边的标号,因为dfs只能给点分配位置,而一棵树每条树边的终点只有一个. ...

  9. SPOJ375 QTREE - Query on a tree

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

随机推荐

  1. 你真的看懂Android事件分发了吗?

    引子 Android事件分发其实是老生常谈了,但是说实话,我觉得很多人都只是懂其大概,模棱两可.本文的目的就是再次从源码层次梳理一下,重点放在ViewGroup的dispatchTouchEvent方 ...

  2. linux下安装cmake方法(2)---直接用命令安装

    1.linux环境下打开网页,输入上网账号密码,确保已经联网 2.打开终端:输入cmake --version,如果出现版本号,表明已经安装,如果显示没有安装cmake,则需要安装 3.在终端里输入: ...

  3. caffe实战笔记

    Caffe简要介绍: Caffe还没有windows版本,所以我需要远程登录linux服务器 Caffe主要处理图片/图片序列 Caffe读取的数据格式 从专用的数据库中读取(lmdb.leveldb ...

  4. Map and HashMap

    1.1.1. Map 接口 java提供了一组可以以键值对(key-value)的形式存储数据的数据结构,这种数据结构称为Map.我们可以把Map看成一个多行两列的表格,其中第一列存放key,第二列存 ...

  5. C#支付宝支付接口H5版(手机网页支付)

    接口官方文档 https://docs.open.alipay.com/203/107090/ 首先在Nuget 安装 Alipay /// <summary>         /// 支 ...

  6. nginx 负载均衡及反向代理

    Nginx简介 Nginx是一款高性能的http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器.由俄罗斯的程序设计师开发,官方测试nginx能够支支撑5万并发链接,并且cpu.内存 ...

  7. 【JavaWeb学习】过滤器Filter

    一.简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静 ...

  8. python 作用域,global与nonlocal的区别

    在Python中并不是所有的语句块中都会产生作用域.只有当变量在Module(模块).Class(类).def(函数)中定义的时候,才会有作用域的概念. 如果在函数中要对全局变量做改变可以使用glob ...

  9. 基于mysql的单据号生成(前缀+日期+自增id+后缀)

    介绍 本次采用mysql处理,性能不是很好,对于高并发有要求的建议不要采用公司一个小项目,需要生成一个单据号,格式为: 日期 + 每日重新自增号,自己考虑了一下每日自增需要考虑并发和持久问题,两种数据 ...

  10. 美食家app开发日记

    民以食为天. 作为一个20年几乎没做过饭的吃货,从这个假期开始,想利用些时间,自己动手尝试,做些好吃的出来,一方面给父母减轻点负担,获得点成就感,一方面体验生活,学学厨艺,感受生活的乐趣和美好,其三, ...