前言
肝了一上午…这是我才学线段树分治的例题…真舒服
题目
温馨提示:首先在UOJ做,LOJ挖数据,BZOJ终极评测。。。
UOJ198
二手剽…
思路
为什么不能用
C
D
Q
CDQ
CDQ 分治做?因为无法减去一个操作的影响(一些计数类型的就可以),或者说信息没有可减性,无法进行转化
考虑线段树合并,如何转化为一个星球的作用时间?
这里的’时间’并不是一个具体的时间,而是
d
f
s
dfs
dfs 序
所有版本构成一个树形结构,那么对于一个星球而言,一次加操作就是在
[
d
f
n
u
,
d
f
n
u
+
s
i
z
u
−
1
]
[dfn_u,dfn_u+siz_u-1]
[dfnu,dfnu+sizu−1] 的区间加,删除同理
但是实际过程中因为题目输入比较特殊,所以可以通过
D
F
S
DFS
DFS 时后一些小操作避免删除(不是重点)
然后通过将修改操作转化为
O
(
n
)
O(n)
O(n) 段连续的,分在
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn) 个线段树节点上
现在就是区间修改,一些单点询问,并且单先询问带限制(即你是拿着
x
0
x_0
x0 去询问的)
考虑处理限制:
m
i
n
{
(
x
−
x
0
)
2
+
c
}
min\{(x-x_0)^2+c\}
min{(x−x0)2+c} 平方项的出现优先考虑斜率凸包相关
m
i
n
{
(
x
−
x
0
)
2
+
c
}
=
m
i
n
{
−
2
x
0
x
+
x
2
+
c
}
+
x
0
2
min\{(x-x_0)^2+c\}=min\{-2 x_0x+x^2+c\}+x_0^2
min{(x−x0)2+c}=min{−2x0x+x2+c}+x02
令
b
=
−
2
x
0
x
i
+
x
i
2
+
c
i
b=-2x_0x_i+x_i^2+c_i
b=−2x0xi+xi2+ci
2
x
0
x
i
+
b
=
x
i
2
+
c
i
2x_0x_i+b=x_i^2+c_i
2x0xi+b=xi2+ci ,求
b
m
i
n
b_{min}
bmin
将每个星球看作 ( x i , x i 2 + c i ) (x_i,x_i^2+c_i) (xi,xi2+ci) 即是求以 k = 2 x 0 k=2x_0 k=2x0 过点的最小截距,维护下凸壳
由于线段树分治已经将修改覆盖相关询问,就能改变一个节点内修改操作的顺序
我选择修改按斜率递减排序,坐标递增排序,单调栈维护就能做到均摊
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
所以总的时间复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
一些细节:
对于横坐标
x
i
x_i
xi 相等的点我们取
y
i
y_i
yi 最小的,返回斜率是注意判断
一些问题:
1.BZOJ老化后我卡常卡得丧心病狂
2.还可以用凸包优化…
代码
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("inline", "no-stack-protector", "unroll-loops")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<cmath>
#include<cstring>
#include<climits>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[(1 << 21) + 1], *p1 = buf, *p2 = buf;
inline LL read() {
bool f=0;LL x=0;char c=getchar();
while(c<'0'||'9'<c){if(c==EOF)exit(0);if(c=='-')f=1;c=getchar();}
while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return !f?x:-x;
}
#define MAXN 500000
#define INF 100000000000000ll
struct node{
int type,id;
}a[MAXN+5];
struct Modify{
int L,R;LL x,y;
friend bool operator < (Modify a,Modify b){return a.x<b.x;}
}M[MAXN+5];
struct Ask{
int id,t,x0;
friend bool operator < (Ask a,Ask b){return a.x0>b.x0;}
}Q[MAXN+5];
int cntm;
LL x[MAXN+5],c[MAXN+5];
int cnt_dfn,dfn[MAXN+5],siz[MAXN+5];
struct Node{
struct Edge{
int nxt,v;
}edge[2*MAXN+5];
int ecnt,head[MAXN+5];
void Addedge(int u,int v){
edge[++ecnt]=(Edge){head[u],v},head[u]=ecnt;
return ;
}
}G,ML,MR;
inline void DFS(register int u){
siz[u]=1,dfn[u]=++cnt_dfn;
if(!a[u].type) ML.Addedge(a[u].id,dfn[u]);
else MR.Addedge(a[u].id,dfn[u]-1);
for(register int i=G.head[u];i;i=G.edge[i].nxt){
register int v=G.edge[i].v;
DFS(v),siz[u]+=siz[v];
}
if(!a[u].type) MR.Addedge(a[u].id,dfn[u]+siz[u]-1);
else ML.Addedge(a[u].id,dfn[u]+siz[u]);
return ;
}
#define lch (u<<1)
#define rch (u<<1|1)
int siz_Stk[4*MAXN+5];
vector<int> Stk[4*MAXN+5];
inline LL Y(register int i,register int j){return M[i].y-M[j].y;}
inline LL X(register int i,register int j){return M[i].x-M[j].x;}
double K(int i,int j){
if(M[i].x==M[j].x)return M[i].y>M[j].y?INF:-INF;
return 1.0*(Y(i,j))/(X(i,j));
}
inline void Insert_M(register int u,register int L,register int R,register int qL,register int qR,register int id){
if(qL<=L&&R<=qR){
register int tp=siz_Stk[u]-1;
while(tp>0&&Y(id,Stk[u][tp])*X(Stk[u][tp],Stk[u][tp-1])<=Y(Stk[u][tp],Stk[u][tp-1])*X(id,Stk[u][tp]))
//while(tp>0&&K(id,Stk[u][tp])<=K(Stk[u][tp],Stk[u][tp-1]))
tp--,Stk[u].pop_back(),siz_Stk[u]--;
Stk[u].push_back(id),siz_Stk[u]++;
return ;
}
register int Mid=(L+R)>>1;
if(qL<=Mid)
Insert_M(lch,L,Mid,qL,qR,id);
if(Mid+1<=qR)
Insert_M(rch,Mid+1,R,qL,qR,id);
return ;
}
LL ans[MAXN+5];
inline LL Query(int u,int L,int R,int p,LL x0){
int tp=siz_Stk[u]-1;
register LL ret=INF;
while(tp>0&&2*x0*X(Stk[u][tp],Stk[u][tp-1])<=Y(Stk[u][tp],Stk[u][tp-1]))
//while(tp>0&&2*x0<=K(Stk[u][tp],Stk[u][tp-1]))
tp--,Stk[u].pop_back(),siz_Stk[u]--;
if(tp!=-1)
ret=M[Stk[u][tp]].y-2*x0*M[Stk[u][tp]].x+x0*x0;
if(L==R) return ret;
register int Mid=(L+R)>>1;
if(p<=Mid)
ret=min(ret,Query(lch,L,Mid,p,x0));
else ret=min(ret,Query(rch,Mid+1,R,p,x0));
return ret;
}
int main(){
int n=read(),m=read();
x[1]=0,c[1]=read();
a[1]=(node){0,1};
for(int i=2;i<=n;i++){
int opt=read();
int fr=read()+1,id=read()+1;
G.Addedge(fr,i);
if(opt==0)
x[id]=read(),read(),read(),c[id]=read();
a[i]=(node){opt,id};
}
DFS(1);
//puts("");
for(register int i=1;i<=n;i++)
for(register int j1=ML.head[i],j2=MR.head[i];j1;j1=ML.edge[j1].nxt,j2=MR.edge[j2].nxt){
//printf("%d %d\n",ML.edge[j1].v,ML.edge[j2].v);
M[++cntm]=(Modify){ML.edge[j1].v,MR.edge[j2].v,x[i],x[i]*x[i]+c[i]};
}
sort(M+1,M+cntm+1);
for(int i=1;i<=cntm;i++)
Insert_M(1,1,n,M[i].L,M[i].R,i);
for(int i=1;i<=m;i++){
int t=read()+1,x0=read();
Q[i]=(Ask){i,t,x0};
}
sort(Q+1,Q+m+1);
for(int i=1;i<=m;i++)
ans[Q[i].id]=Query(1,1,n,dfn[Q[i].t],Q[i].x0);
for(int i=1;i<=m;i++)
printf("%lld\n",ans[i]);
return 0;
}