第一次写线段树分治的题目,没想到是道这么毒的题233

首先发现题目里的\((x,y,z,c)\)就是在放屁,只有\((x,c)\)是有用的

因此我们可以把题意转化为,在某一个时间节点上,求出所有元素的

\[\min((X-x_i)^2+c_i)
\]

稍加观察会发现时间节点是成一棵树的形态的,因此对于一个星球,它存在的时间节点在树上必然是两个区间(第一次出现的子树减去第一次删除的子树,当然没删除的话就是一个区间)

因此我们利用线段树分治的思想,把这些区间扔到线段树里,考虑用线段树分治来做

然后考虑答案怎么计算,这种带平方的想想都是斜率优化或者凸包一类的东西,我们展开式子:

\[(X-x_i)^2+c_i=X^2-2Xx_i+x_i^2+c_i=b
\]

那么就有:

\[2Xx_i+b=X^2+x_i^2+c_i
\]

于是我们可以把\((x_i,X^2+x_i^2+c_i)\)看做一个决策点,现在我们需要一条斜率为\(2X\)的直线去穿过这个点,然后是的截距最小

那么我们只需要维护一个凸包,让后每次找到斜率第一个大于\(2X\)的线段,然后前面的那个点就是最优决策点

那么大致思路就来了,如果你写了可持久化平衡树维护凸包就有了时间三个\(\log\),空间两个\(\log\)的算法

然后我们发现写动态凸包就是SB,因为插入点的顺序是由我们自己决定的,因此直接给所有星球按\(x_i\)排序插入即可,因此变成了插入一个\(\log\),询问两个\(\log\)

然后我们发现写凸包上二分就是SB,因为询问的顺序也是由我们自己决定的,因此之间把询问的\(X\)排序后单调移动端点即可

综上,时空复杂度都是\(O(n\log n)\)的,但需要一定的常数以及特判

#include<cstdio>
#include<cctype>
#include<vector>
#include<iostream>
#include<algorithm>
#define int long long
#define RI register int
#define CI const int&
#define Tp template <typename T>
#define pb push_back
using namespace std;
const int N=500005,INF=1e18;
struct edge
{
int to,nxt;
}e[N<<1]; int n,m,head[N],cnt,c[N],vx[N],id[N],a[N],opt,x,y,z,u,v;
struct ques
{
int pos,val,id;
friend inline bool operator < (const ques& A,const ques& B)
{
return A.val<B.val;
}
}q[N]; int dfn[N],idx,ans[N]; vector <int> L[N],R[N];
class FileInputOutput
{
private:
static const int S=1<<18;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
#define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=Fout)++=ch))
char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[25];
public:
inline FileInputOutput() { Ftop=Fout; Fend=Fout+S; }
Tp inline void read(T& x)
{
x=0; char ch; int flag=1; while (!isdigit(ch=tc())) if (ch=='-') flag=-1;
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc())); x*=flag;
}
Tp inline void write(T x)
{
RI ptop=0; while (pt[++ptop]=x%10,x/=10);
while (ptop) pc(pt[ptop--]+48); pc('\n');
}
inline void flush(void)
{
fwrite(Fout,1,Ftop-Fout,stdout);
}
#undef tc
#undef pc
}F;
inline void addedge(CI x,CI y)
{
e[++cnt]=(edge){y,head[x]}; head[x]=cnt;
e[++cnt]=(edge){x,head[y]}; head[y]=cnt;
}
#define to e[i].to
inline void DFS(CI now=1,CI fa=0)
{
dfn[now]=++idx; if (id[now]>0) L[id[now]].pb(idx); if (id[now]<0) R[-id[now]].pb(idx-1);
for (RI i=head[now];i;i=e[i].nxt) if (to!=fa) DFS(to,now);
if (id[now]>0) R[id[now]].pb(idx); if (id[now]<0) L[-id[now]].pb(idx+1);
}
#undef to
inline bool cmpid(CI x,CI y)
{
return vx[x]<vx[y];
}
class Segment_Tree
{
private:
struct segment
{
int head,tail; vector <int> pnt;
}node[3*N+10];
#define H(x) node[x].head
#define T(x) node[x].tail
#define S(x) node[x].pnt.size()
#define P(x,y) node[x].pnt[y]
#define TN CI now=1,CI l=1,CI r=n
#define LS now<<1,l,mid
#define RS now<<1|1,mid+1,r
inline int sqr(CI x)
{
return x*x;
}
inline long double slope(CI x,CI y)
{
return 1.0*(sqr(vx[x])+c[x]-sqr(vx[y])-c[y])/(vx[x]-vx[y]);
}
public:
inline void build(TN)
{
T(now)=-1; if (l==r) return; int mid=l+r>>1; build(LS); build(RS);
}
inline void insert(CI beg,CI end,CI id,TN)
{
if (beg==l&&r==end)
{
if (S(now)<=T(now)+5) node[now].pnt.resize(T(now)+5);
if (H(now)<=T(now)&&vx[P(now,T(now))]==vx[id])
{ if (c[P(now,T(now))]<=c[id]) return; --T(now); }
while (H(now)<T(now)&&slope(P(now,T(now)),id)<slope(P(now,T(now)-1),P(now,T(now))))
--T(now); P(now,T(now)+1)=id; ++T(now); return;
}
int mid=l+r>>1; if (end<=mid) insert(beg,end,id,LS);
else if (beg>mid) insert(beg,end,id,RS); else
insert(beg,mid,id,LS),insert(mid+1,end,id,RS);
}
inline int query(CI pos,CI val,TN)
{
while (H(now)<T(now)&&slope(P(now,H(now)),P(now,H(now)+1))<=2.0*val) ++H(now);
int ret=INF; if (H(now)<=T(now)&&S(now)) ret=sqr(val-vx[P(now,H(now))])+c[P(now,H(now))];
if (l==r) return ret; int mid=l+r>>1; return min(ret,pos<=mid?query(pos,val,LS):query(pos,val,RS));
}
#undef H
#undef T
#undef S
#undef P
#undef TN
#undef LS
#undef RS
}SEG;
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i,j; for (F.read(n),F.read(m),F.read(c[0]),i=1;i<n;++i)
{
F.read(opt); F.read(u); F.read(v); if (!opt)
F.read(vx[v]),F.read(y),F.read(z),F.read(c[v]),id[i]=v,addedge(u,i);
else id[i]=-v,addedge(u,i);
}
for (DFS(),SEG.build(),i=1;i<=n;++i) a[i]=i; sort(a+1,a+n+1,cmpid);
for (SEG.insert(1,n,0),i=1;i<=n;++i)
for (y=a[i],z=L[y].size(),j=0;j<z;++j)
if (L[y][j]<=R[y][j]) SEG.insert(L[y][j],R[y][j],y);
for (i=1;i<=m;++i) F.read(q[i].pos),F.read(q[i].val),q[i].id=i;
for (sort(q+1,q+m+1),i=1;i<=m;++i)
ans[q[i].id]=q[i].pos?SEG.query(dfn[q[i].pos],q[i].val):q[i].val*q[i].val+c[0];
for (i=1;i<=m;++i) F.write(ans[i]); return F.flush(),0;
}

Luogu P5416 [CTSC2016]时空旅行的更多相关文章

  1. [UOJ198][CTSC2016]时空旅行

    uoj description 你要维护若干个集合,每个集合都是有一个编号比他小的集合扩展而来,扩展内容为加入一个新的元素\((x,c)\)或者删除一个已有元素.集合的扩展关系之间构成一个树形结构. ...

  2. [CTSC2016]时空旅行

    description 题面 solution 线段树分治+斜率优化毒瘤题 题目可以简化为: 你要维护一个包含元素\((x,c)\)的集合 修改操作为从以前的一个版本更新,修改内容为添加或删除一个元素 ...

  3. [CTSC2016]时空旅行(线段树+凸包)

    应该是比较套路的,但是要A掉仍然不容易. 下面理一下思路,思路清楚了也就不难写出来了. 0.显然y,z坐标是搞笑的,忽略即可. 1.如果x不变,那么直接set即可解决. 2.考虑一个空间和询问x0,通 ...

  4. CTSC2016时空旅行

    当时看这道题AC的人数比较多,就开了这道题. 很容易发现是这是一个有关凸包的题. 然后不知道怎么维护凸包,一直在想cdq,感觉复杂度不行,于是被这玩意难住了…… 幸好有亲学长yyh造福人类的题解:ht ...

  5. @loj - 2987@ 「CTSC2016」时空旅行

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 2045 年,人类的技术突飞猛进,已经找到了进行时空旅行的方法. ...

  6. 【CTSC2016】时空旅行

    链接 http://uoj.ac/problem/198 题解 首先要发现答案要我们求这个式子: \[ ans=min\bigl((x_i-x)^2+c_i\bigr) \] 显而易见的是这种时空嫁接 ...

  7. uoj198【CTSC2016】时空旅行

    传送门:http://uoj.ac/problem/198 [题解] 首先y.z是没有用的.. 然后式子就是w = (x0-xi)^2+ci的最小值,化出来可以变成一个直线的形式. 然后我们可以用线段 ...

  8. 【UOJ #198】【CTSC 2016】时空旅行

    http://uoj.ac/problem/198 (先补一下以前的题解) 这道题5分暴力好写好调,链上部分分可以用可持久化线段树,每次旅行\(x\)值相同的可以用标记永久化线段树.我还听到某些神犇说 ...

  9. [UOJ198]时空旅行

    看懂题目就知道$y,z$是没用的,这题相当于是给一堆$(x_i,c_i)$和询问$x_q$,要求$(x_q-x_i)^2+c_i$的最大值 先把这个式子拆开:$-2x_ix_q+x_i^2+c_i+x ...

随机推荐

  1. C语言解决汉诺塔问题!

    很难受,看了很多资料才明白..... 对这个问题分析,发现思路如下:有n个黄金盘,要先把n-1个弄到B柱上,再把第n个弄到C柱上,然后把n-1个借助A柱弄到C柱上. 实现的函数如下: void f(i ...

  2. python-openCV 绘制图形

    文档链接:https://docs.opencv.org/trunk/dc/da5/tutorial_py_drawing_functions.html 文档描述了OpenCV的几个绘图功能: 绘制圆 ...

  3. Luogu P5408 【模板】第一类斯特林数·行

    为什么要做这题呢,当然是有用啊qwq 首先我们考虑非常经典的式子: \[x^{\overline{n}}=\sum_i \left[^n_i\right] x^i\] 然后上倍增: \[x^{\ove ...

  4. 1+X证书web前端开发中级对应课程分析

    官方QQ群 1+x 证书 Web 前端开发 JavaScript 专项练习 http://blog.zh66.club/index.php/archives/198/ 1+x 证书 Web 前端开发初 ...

  5. Linux-Bash终端快捷键

    ^C 终正在运行的进程或放弃当前编辑的命令^U 将光标所在字符到行首之间的所有字符删除,可以使用^E到行尾再^U来删除整行内容^Z 将前台运行的进程放入背景并暂停^D 发送EOF,结束当前输入流,如果 ...

  6. 黄聪:wordpress登录后台后load-scripts.php载入缓慢

    今天一个微信群里一个好友问大鸟,他的wordpess后台载入非常缓慢,缓慢到什么程度,我们看图: 这个真的是超级慢了,这类问题怎么解决呢,我们登录后台后,按下F12打开控制台,接着点击network, ...

  7. oracle 中 to_date 函数的用法

    常犯错的使用方法. to_date('2019-08-12 22:05:','yyyy-MM-dd HH24:mm:ss') Oracle中会引起错误:"ORA 01810 格式代码出现两次 ...

  8. oracle学习笔记(八)——结果集元数据ResultSetMetaData以及ResultSet转为对应的实体类框架

    介绍 可用于获取关于 ResultSet 对象中列的类型和属性信息的对象,在持久框层框架(如:mybatis, hibernate)中被广泛的应用. 常用方法 int getColumnCount() ...

  9. Python爬取十四万条书籍信息告诉你哪本网络小说更好看

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: TM0831 PS:如有需要Python学习资料的小伙伴可以加点击 ...

  10. JQuery操作样式以及JQuery事件机制

    1.操作样式     1.1 css的操作     功能:设置或者修改样式,操作的是style属性 操作单个样式 // name:需要设置的样式名称 // value:对应的样式值 // $obj.c ...