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

Posted HocRiser

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CTSC2016]时空旅行(线段树+凸包)相关的知识,希望对你有一定的参考价值。

应该是比较套路的,但是要A掉仍然不容易。

下面理一下思路,思路清楚了也就不难写出来了。

 

0.显然y,z坐标是搞笑的,忽略即可。

1.如果x不变,那么直接set即可解决。

2.考虑一个空间和询问x0,通过化式子发现实际上就是:把每个星球看成一个一次函数,其实是在询问这个空间内的所有一次函数在x0处的最小值。

3.这个显然是一个凸包,所以我们需要对每个空间维护一个凸包,由空间整体呈树状,可以想到用DFS序+线段树维护区间。

4.预处理出每个星球的存在范围,在线段树上永久化标记。查询时依次递归求最小值。

5.关于线段树上如何存凸包,可以先扫一遍预留出空间,也可以直接像http://www.cnblogs.com/HocRiser/p/8549456.html一样用vector存,后者可能会慢一点,开了读入外挂就过了。

 1 #include<cstdio>
 2 #include<vector>
 3 #include<algorithm>
 4 #define ls (x<<1)
 5 #define rs (ls|1)
 6 #define lson ls,L,mid
 7 #define rson rs,mid+1,R
 8 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 9 typedef long long ll;
10 using namespace std;
11 
12 const int N=500010;
13 const ll inf=1000000000000000000ll;
14 int n,m,cnt,x,y,c,tim,op,fr,d,id[N],L[N],R[N],X[N],K[N];
15 int h[N],nxt[N],pos[N],to[N],st[N<<2],ed[N<<2],q[N];
16 ll a[N],b[N],ans[N];
17 vector<int>T[N<<2],V[N];
18 
19 ll rd(){
20     ll x=0; bool t=0; char ch=getchar();
21     while (ch<\'0\' || ch>\'9\') t|=(ch==\'-\'),ch=getchar();
22     while (ch>=\'0\' && ch<=\'9\') x=x*10+ch-\'0\',ch=getchar();
23     if (t) return -x; else return x;
24 }
25 
26 bool cmp0(int x,int y){ return L[x]<L[y]; }
27 bool cmp1(int x,int y){ return a[x]>a[y] || (a[x]==a[y] && b[x]>b[y]); }  
28 bool cmp2(int a,int b){ return X[a]<X[b]; }
29 bool Cmp(int x,int y,int z){ return ((b[y]-b[x])*(a[y]-a[z])>=(b[z]-b[y])*(a[x]-a[y])); }
30 
31 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
32 
33 void dfs(int x){ L[x]=++tim; for (int i=h[x]; i; i=nxt[i]) dfs(to[i]); R[x]=tim; }
34 
35 void build(int x,int L,int R){
36     ed[x]=-1;
37     if (L==R) { pos[L]=x; return; }
38     int mid=(L+R)>>1; build(lson); build(rson);
39 }
40 
41 void ins(int x,int L,int R,int l,int r,int k){
42     if (L==l && r==R){
43         int &j=ed[x];
44         for (; st[x]<j && Cmp(T[x][j-1],T[x][j],k); j--,T[x].pop_back());
45         j++; T[x].push_back(k);
46         return;
47     }
48     int mid=(L+R)>>1;
49     if (r<=mid) ins(lson,l,r,k);
50     else if (l>mid) ins(rson,l,r,k);
51         else ins(lson,l,mid,k),ins(rson,mid+1,r,k);
52 }
53 
54 ll que(int k,int x){
55     ll ans=inf;
56     for (int i=pos[k]; i; i>>=1){
57         int &j=st[i];
58         for (; j<ed[i] && (a[T[i][j]]-a[T[i][j+1]])*x>=b[T[i][j+1]]-b[T[i][j]]; j++);
59         if (j<=ed[i]) ans=min(ans,a[T[i][j]]*x+b[T[i][j]]);
60     }
61     return ans;
62 }
63 
64 int main(){
65     freopen("travel.in","r",stdin);
66     freopen("travel.out","w",stdout);
67     n=rd(); m=rd(); b[1]=rd(); id[1]=1;
68     rep(i,2,n){
69         op=rd(); fr=rd()+1; d=rd()+1; add(fr,i);
70         if (op) V[d].push_back(i);
71         else id[d]=i,x=rd(),rd(),rd(),c=rd(),a[d]=-2ll*x,b[d]=1ll*x*x+c;
72     }
73     dfs(1); build(1,1,n);
74     rep(i,1,n) q[i]=i; sort(q+1,q+n+1,cmp1);
75     rep(l,1,n) if (id[q[l]]){
76         int i=q[l];
77         sort(V[i].begin(),V[i].end(),cmp0); int k=L[id[i]];
78         for (vector<int>::iterator it=V[i].begin(); it!=V[i].end(); k=R[*it]+1,it++)
79             if (k<L[*it]) ins(1,1,n,k,L[*it]-1,i);
80         if (k<=R[id[i]]) ins(1,1,n,k,R[id[i]],i);
81     }
82     rep(i,1,m) q[i]=i,x=rd(),y=rd(),K[i]=L[x+1],X[i]=y;
83     sort(q+1,q+m+1,cmp2);
84     rep(i,1,m) ans[q[i]]=que(K[q[i]],X[q[i]])+1ll*X[q[i]]*X[q[i]];
85     rep(i,1,m) printf("%lld\\n",ans[i]);
86     return 0;
87 }

 

以上是关于[CTSC2016]时空旅行(线段树+凸包)的主要内容,如果未能解决你的问题,请参考以下文章

luogu P5416 [CTSC2016]时空旅行

[CTSC2016]时空旅行

uoj198CTSC2016时空旅行

Luogu P5416 [CTSC2016]时空旅行

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

线段树分治