【NowCoder368E】车站(线段树)

题面

牛客网

题解

链交的结果显然和求解的顺序无关,因此我们可以拿线段树维护区间链的链交结果。

然后怎么求解最远点。

维护链交的时候再记录两个点表示到达链交两个端点的最远点编号,合并的时候也维护一下。

这样子就可以啦。

然后分类讨论论论论论论论论一下就好了。

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 100100
#define lson (now<<1)
#define rson (now<<1|1)
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Line{int v,next;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int st[20][MAX<<1],lg[MAX<<1],sum,p[20][MAX];
int n,m,Q,dep[MAX],dfn[MAX],low[MAX];
void dfs(int u,int ff)
{
st[0][dfn[u]=++sum]=u;dep[u]=dep[ff]+1;p[0][u]=ff;
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)
dfs(e[i].v,u),st[0][++sum]=u;
low[u]=sum;
}
int Chk1(int a,int b){return dep[a]<dep[b]?a:b;}
int Chk2(int a,int b){return dep[a]>dep[b]?a:b;}
int LCA(int u,int v)
{
u=dfn[u],v=dfn[v];if(u>v)swap(u,v);
int l=lg[v-u+1];
return Chk1(st[l][u],st[l][v-(1<<l)+1]);
}
int Kth(int x,int K)
{
for(int i=lg[n];~i;--i)
if(K&(1<<i))x=p[i][x];
return x;
}
int Dis(int u,int v){return dep[u]+dep[v]-2*dep[LCA(u,v)];}
struct Data{int x,y,z,sx,sy;}t[MAX<<2];
Data Make(int x,int y){return (Data){x,y,LCA(x,y),x,y};}
Data operator+(Data a,Data b)
{
Data c;c.x=-1;if(a.x==-1||b.x==-1)return c;
if(dep[a.z]<dep[b.z])swap(a,b);
if(LCA(a.z,b.x)!=a.z&&LCA(a.z,b.y)!=a.z)return c;
c.x=Chk2(LCA(a.x,b.x),LCA(a.x,b.y));
c.y=Chk2(LCA(a.y,b.x),LCA(a.y,b.y));
if(Dis(a.sx,c.x)>Dis(a.sx,c.y))swap(a.sx,a.sy);
if(Dis(b.sx,c.x)>Dis(b.sx,c.y))swap(b.sx,b.sy);
c.sx=(Dis(c.x,a.sx)<Dis(c.x,b.sx))?b.sx:a.sx;
c.sy=(Dis(c.y,a.sy)<Dis(c.y,b.sy))?b.sy:a.sy;
c.z=LCA(c.x,c.y);return c;
}
void Build(int now,int l,int r)
{
if(l==r){int x=read(),y=read();t[now]=Make(x,y);return;}
int mid=(l+r)>>1;
Build(lson,l,mid);Build(rson,mid+1,r);
t[now]=t[lson]+t[rson];
}
void Modify(int now,int l,int r,int p)
{
if(l==r){int x=read(),y=read();t[now]=Make(x,y);return;}
int mid=(l+r)>>1;
if(p<=mid)Modify(lson,l,mid,p);
else Modify(rson,mid+1,r,p);
t[now]=t[lson]+t[rson];
}
Data Query(int now,int l,int r,int L,int R)
{
if(l==L&&r==R)return t[now];
int mid=(l+r)>>1;
if(R<=mid)return Query(lson,l,mid,L,R);
if(L>mid)return Query(rson,mid+1,r,L,R);
return Query(lson,l,mid,L,mid)+Query(rson,mid+1,r,mid+1,R);
}
int Calc(Data a)
{
if(a.x==-1)return -1;
int D=Dis(a.sx,a.sy),d=Dis(a.x,a.y),dx=Dis(a.x,a.sx),dy=Dis(a.y,a.sy);
if(dx>dy)swap(dx,dy),swap(a.x,a.y),swap(a.sx,a.sy);
if(dy>=dx+d)return a.y;
int l,r;
l=D/2-dx,r=(D+1)/2-dy;
int A=(dep[a.x]-dep[a.z]>=l)?Kth(a.x,l):Kth(a.y,r);
l=(D+1)/2-dx,r=D/2-dy;
int B=(dep[a.x]-dep[a.z]>=l)?Kth(a.x,l):Kth(a.y,r);
return min(A,B);
}
int main()
{
n=read();m=read();
for(int i=2;i<=n+n;++i)lg[i]=lg[i>>1]+1;
for(int i=1,u,v;i<n;++i)u=read(),v=read(),Add(u,v),Add(v,u);
dfs(1,0);
for(int j=1;j<=lg[sum];++j)
for(int i=1;i+(1<<j)-1<=sum;++i)
st[j][i]=Chk1(st[j-1][i],st[j-1][i+(1<<(j-1))]);
for(int j=1;j<=lg[sum];++j)
for(int i=1;i<=n;++i)
p[j][i]=p[j-1][p[j-1][i]];
Build(1,1,m);
Q=read();
while(Q--)
{
int opt=read(),x=read();
if(opt==1)printf("%d\n",Calc(Query(1,1,m,x,read())));
else Modify(1,1,m,x);
}
return 0;
}

【NowCoder368E】车站(线段树)的更多相关文章

  1. FOJ2022车站 线段树区间合并

    http://acm.fzu.edu.cn/problem.php?pid=2022 刚开始MLE,用map对应,果断爆内存了,然后改用去重,离散化, lowbound查找元素位置,速度还不错,不过p ...

  2. Codeforces 675E Trains and Statistic(DP + 贪心 + 线段树)

    题目大概说有n(<=10W)个车站,每个车站i卖到车站i+1...a[i]的票,p[i][j]表示从车站i到车站j所需买的最少车票数,求所有的p[i][j](i<j)的和. 好难,不会写. ...

  3. 线段树+dp+贪心 Codeforces Round #353 (Div. 2) E

    http://codeforces.com/contest/675/problem/E 题目大意:有n个车站,每个车站只能买一张票,这张票能从i+1到a[i].定义p[i][j]为从i到j所需要买的最 ...

  4. TZOJ 3315 买火车票(线段树区间最小值)

    描述 Byteotian州铁道部决定赶上时代,为此他们引进了城市联网.假设城市联网顺次连接着n 个市从1 到n 编号(起始城市编号为1,终止城市编号为n).每辆火车有m个座位且在任何两个运送更多的乘客 ...

  5. 【CF675E】Trains and Statistic(贪心,DP,线段树优化)

    题意:a[i]表示从第i个车站可以一张票到第[i+1,a[i]]这些车站;p[i][j]表示从第i个车站到第j个车站的最少的票数,现在要求∑dp[i][j](1<=i<=n,i<j& ...

  6. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

  7. codevs 1082 线段树练习 3(区间维护)

    codevs 1082 线段树练习 3  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...

  8. codevs 1576 最长上升子序列的线段树优化

    题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...

  9. codevs 1080 线段树点修改

    先来介绍一下线段树. 线段树是一个把线段,或者说一个区间储存在二叉树中.如图所示的就是一棵线段树,它维护一个区间的和. 蓝色数字的是线段树的节点在数组中的位置,它表示的区间已经在图上标出,它的值就是这 ...

随机推荐

  1. javascript重定向页面并用post方法传递消息

    javascript中重定向页面得方法很多,同时能传递消息的也不少:但可用post方法传递的我只找到两种: 第一种方法:用document.write在 JavaScript函数中,用document ...

  2. 学习yii2.0——事件

    参考:https://www.yiichina.com/doc/guide/2.0/concept-events 事件 yii框架中的事件定义和JavaScript中的事件定义差不多:为某个事件绑定一 ...

  3. ubuntu安装chkconfig.deb系统服务管理工具

    chkconfig简介:chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息. 参数用法:   --add 增加所指定的系统服务,让chkconfig指令得以管理它,并同时在系统 ...

  4. Farm Irrigation

    题目:Farm Irrigation 题目链接:http://210.34.193.66:8080/vj/Problem.jsp?pid=1494 题目思路:并查集 #include<stdio ...

  5. Vue2.0 子组件和父组件之间的传值

    Vue是一个轻量级的渐进式框架,对于它的一些特性和优点在此就不做赘述,本篇文章主要来探讨一下Vue子父组件通信的问题 首先我们先搭好开发环境,我们首先得装好git和npm这两个工具(如果有不清楚的同学 ...

  6. Flutter常用插件

    Dio Dio是一个强大的Dart Http请求库,支持Restful API.FormData.拦截器.请求取消等操作.视频中将全面学习和使用Dio的操作. Flutter_swiper swipe ...

  7. flutter开发vscode用模拟器调试

    android studio的太重,我装的是android sdk,使用avd的模拟器启动黑屏 启动夜神模拟器(已卸载) 建立连接: adb connect 127.0.0.1:62001    (夜 ...

  8. linux audit审计(8)--ausearch搜索audit日志文件

    ausearch这个工具,可以针对指定的事件来搜索audit日志文件.默认情况下,ausearch搜索/var/log/audit/audit.log这个文件. The ausearch utilit ...

  9. k8s使用glusterfs做存储

    一.安装glusterfs https://www.cnblogs.com/zhangb8042/p/7801181.html 环境介绍; centos 7 [root@k8s-m ~]# cat / ...

  10. 集合之LinkedList(含JDK1.8源码分析)

    一.前言 LinkedList是基于链表实现的,所以先讲解一下什么是链表.链表原先是C/C++的概念,是一种线性的存储结构,意思是将要存储的数据存在一个存储单元里面,这个存储单元里面除了存放有待存储的 ...