BZOJ 4515 游戏

Link

去年在考场上精心写了一个暴力,得了5分 究其原因,是因为: 1. 题读反了 2. 函数的参数列表里应该写ll写了int

当时还根本没听说过超哥线段树这种技巧 # Solution 树链剖分之后,一条链上的点到根节点距离的前缀和\(len[]\)是递增的,就可以看做是\(x\)坐标,可以上超哥线段树了。 对于\(a\times dist(s,r)+b\)这个操作,把链拆成两半 对于\(s\)\(lca\)这一段,其增加的值为\(a\times (len[s]-len[lca])+b=-a\times len[lca]+a\times len[s]+b\),相当于在线段树上添加一条直线 对于另一段,增加的值为\(a\times (len[r]-len[lca]+len[s]-len[lca])+b=a\times len[r]-2a\times len[lca]+b\),相当于在线段树上添加一条直线 对于区间查询\([l,r]\),对于查询时途径的节点都算一下直线在\(l,r\)处的取值,用来更新答案。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
//Code by Lucida
#include<bits/stdtr1c++.h>
#define get(x) scanf("%d",&x)
#define put(x) printf("%d",x)
#define get64(x) scanf("%lld",&x)
#define put64(x) printf("%lld",x)
typedef long long int64;
template <class T> inline bool chkmx(T &a,const T &b){return a<b?a=b,1:0;}
template <class T> inline bool chkmn(T &a,const T &b){return a>b?a=b,1:0;}
const int64 INF=123456789123456789LL;
const int MAXN=1e5+11;
using std::swap;
using std::min;
int64 v[MAXN];
struct Edge
{
Edge *pre;int to,v;
Edge(Edge *pre,int to,int v):pre(pre),to(to),v(v){}
}*id[MAXN];
void Adde(int f,int t,int v)
{
static Edge *Me=(Edge*)malloc((MAXN<<1)*sizeof(Edge));
id[f]=new(Me++) Edge(id[f],t,v);
id[t]=new(Me++) Edge(id[t],f,v);
}
struct Line
{
int64 k,b;
Line(){k=0,b=INF;}Line(int64 k,int64 b):k(k),b(b){}
int64 operator ()(int64 x){return k*x+b;}
};
namespace _SegTree_
{
const int SIZE=MAXN<<2;
struct Node
{
Node *son[2];
int64 minv;
Line ln;
Node(){minv=INF;son[0]=son[1]=0;}
void Up(){chkmn(minv,min(son[0]->minv,son[1]->minv));}
void *operator new(size_t);
}*Pool=(Node*)malloc(SIZE*sizeof(Node)),*Me=Pool,*null=new Node;
void *Node::operator new(size_t){return Me++;}
struct SegTree
{
int L,R;Node *root;
SegTree(){}SegTree(int,int);
void Build(Node*&,int L,int R);
void Append(Node*,int L,int R,Line ln);
void Insert(Node*,int,int,int,int,Line);
void Insert(int l,int r,Line ln){Insert(root,L,R,l,r,ln);}
int64 Access(Node*,int,int,int,int);
int64 Access(int l,int r){return Access(root,L,R,l,r);}
};
SegTree::SegTree(int L,int R):L(L),R(R){Build(root,L,R);}
void SegTree::Build(Node *&pos,int L,int R)
{
pos=new Node;
if(L!=R)
{
int Mid=(L+R)>>1;
Build(pos->son[0],L,Mid);
Build(pos->son[1],Mid+1,R);
}
}
void SegTree::Append(Node *pos,int L,int R,Line ln)
{
if(!pos) return;
chkmn(pos->minv,min(ln(v[L]),ln(v[R])));
Line hl=ln,hr=pos->ln;
if(hl(v[L])>hr(v[L])) swap(hl,hr);
int Mid=(L+R)>>1;double x=-(1.0*hr.b-hl.b)/(1.0*hr.k-hl.k);
if(!(v[L]<=x && x<=v[R])) {pos->ln=hl;return;}
if(x<=v[Mid]) Append(pos->son[0],L,Mid,hl),pos->ln=hr;
else Append(pos->son[1],Mid+1,R,hr),pos->ln=hl;
}
void SegTree::Insert(Node *pos,int L,int R,int l,int r,Line ln)
{
if(L==l && R==r) Append(pos,L,R,ln);
else
{
int Mid=(L+R)>>1;
if(r<=Mid) Insert(pos->son[0],L,Mid,l,r,ln);
else if(Mid+1<=l) Insert(pos->son[1],Mid+1,R,l,r,ln);
else Insert(pos->son[0],L,Mid,l,Mid,ln),Insert(pos->son[1],Mid+1,R,Mid+1,r,ln);
pos->Up();
}
}
int64 SegTree::Access(Node *pos,int L,int R,int l,int r)
{
if(L==l && R==r) return pos->minv;
else
{
int Mid=(L+R)>>1;int64 res=min(pos->ln(v[l]),pos->ln(v[r]));
if(r<=Mid) chkmn(res,Access(pos->son[0],L,Mid,l,r));
else if(Mid+1<=l) chkmn(res,Access(pos->son[1],Mid+1,R,l,r));
else chkmn(res,min(Access(pos->son[0],L,Mid,l,Mid),Access(pos->son[1],Mid+1,R,Mid+1,r)));
return res;
}
}
}using _SegTree_::SegTree;
namespace _Divide_
{
struct Node{int top;}*Me=(Node*)malloc(MAXN*sizeof(Node)),*cn[MAXN];
int fa[MAXN],dep[MAXN],sz[MAXN],prefer[MAXN],dfs[MAXN],lbd[MAXN],rbd[MAXN],dc;
int64 len[MAXN];
SegTree seg;
void DFS(int pos)
{
sz[pos]=1;
for(Edge *e=id[pos];e;e=e->pre)
{
int u=e->to;
if(u==fa[pos]) continue;
fa[u]=pos;
dep[u]=dep[pos]+1;
len[u]=len[pos]+e->v;
DFS(u);
if(sz[u]>sz[prefer[pos]]) prefer[pos]=u;
sz[pos]+=sz[u];
}
}
void Assign(int pos)
{
dfs[++dc]=pos;
lbd[pos]=dc;
if(prefer[pos])
{
Assign(prefer[pos]),cn[pos]=cn[prefer[pos]];
for(Edge *e=id[pos];e;e=e->pre)
{
int u=e->to;
if(u==fa[pos] || u==prefer[pos]) continue;
Assign(u),cn[u]->top=u;
}
}
else
cn[pos]=new(Me++) Node;
rbd[pos]=dc;
}
void Divide()
{
DFS(1);
Assign(1),cn[1]->top=1;
seg=SegTree(1,dc);
for(int i=1;i<=dc;++i) v[i]=len[dfs[i]];
}
int LCA(int p1,int p2)
{
while(cn[p1]!=cn[p2])
dep[cn[p1]->top]>dep[cn[p2]->top]?p1=fa[cn[p1]->top]:p2=fa[cn[p2]->top];
return dep[p1]<dep[p2]?p1:p2;
}
void Modify(int bot,int top,Line ln)
{
while(cn[bot]!=cn[top])
{
seg.Insert(lbd[cn[bot]->top],lbd[bot],ln);
bot=fa[cn[bot]->top];
}
seg.Insert(lbd[top],lbd[bot],ln);//写反了??
}
void Modify(int s,int t,int64 a,int64 b)
{
int lca=LCA(s,t);
Modify(s,lca,Line(-a,a*len[s]+b));
Modify(t,lca,Line(a,a*(-2*len[lca]+len[s])+b));
}
int64 Query(int p1,int p2)
{
int64 res=INF;
while(cn[p1]!=cn[p2])
{
if(dep[cn[p1]->top]<dep[cn[p2]->top]) swap(p1,p2);
chkmn(res,seg.Access(lbd[cn[p1]->top],lbd[p1]));
p1=fa[cn[p1]->top];
}
if(lbd[p1]>lbd[p2]) swap(p1,p2);
chkmn(res,seg.Access(lbd[p1],lbd[p2]));
return res;
}
}using namespace _Divide_;
int main()
{
int n,m;get(n),get(m);
for(int i=1;i<=n-1;++i)
{
int u,v,w;get(u),get(v),get(w);
Adde(u,v,w);
}
Divide();
for(int i=1;i<=m;++i)
{
int opt,s,t;
int64 a,b;
get(opt),get(s),get(t);
if(opt==1)
{
get64(a),get64(b);
Modify(s,t,a,b);
}
else
{
int64 Ans=Query(s,t);
put64(Ans),putchar('\n');
}
}
return 0;
}

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2017 Hey,Lucida here. All Rights Reserved.

Lucida Lu 保留所有权利