21.6.13 t2
tag:二分,模拟,李超线段树,倍增
max的变化只有最多n次,直接模拟。。
用二分可以找出每个点作为mx的时间段,然后用倍增去跳
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void Read(T &n){
char ch; bool flag=false;
while(!isdigit(ch=getchar())) if(ch=='-')flag=true;
for(n=ch^48; isdigit(ch=getchar()); n=(n<<1)+(n<<3)+(ch^48));
if(flag) n=-n;
}
#define no !
typedef long long ll;
enum{
MAXN = 100005
};
struct seg{
ll k, b; int id;
seg(ll k=0, ll b=0, int id=0):k(k),b(b),id(id){}
inline ll f(ll x){return k*x+b;}
}a[MAXN];
struct node{seg v; int lc, rc;}t[30*MAXN];
int node_cnt, root;
inline char bigg(seg a, seg b, ll x){
if(a.f(x) > b.f(x)) return true;
if(a.f(x)==b.f(x) and a.id>b.id) return true;
return false;
}
void Insert(int &x, int head, int tail, seg k){
if(!x) return x = ++node_cnt, t[x].v = k, void();
int mid = head+tail >> 1;
if(bigg(k,t[x].v,mid)) swap(t[x].v,k);
if(bigg(t[x].v,k,head) and bigg(t[x].v,k,tail)) return;
if(bigg(k,t[x].v,head)) Insert(t[x].lc,head,mid,k);
if(bigg(k,t[x].v,tail)) Insert(t[x].rc,mid+1,tail,k);
}
seg Query(int x, int head, int tail, int pos){
if(!x) return seg(0,0);
int mid = head+tail >> 1; seg res;
if(pos<=mid) res = Query(t[x].lc,head,mid,pos);
if(mid<pos) res = Query(t[x].rc,mid+1,tail,pos);
if(bigg(t[x].v,res,pos)) res = t[x].v;
return res;
}
int n, m;
int nowmx=-1, nowpos=0, lst;
struct upt{
int t, opt;
inline bool operator <(const upt &k)const{return t<k.t;}
}q[MAXN<<1];
int qcnt;
int ans[MAXN];
struct _{
int nxt, to;
_(int nxt=0, int to=0):nxt(nxt),to(to){}
}edge[MAXN<<1];
int fst[MAXN], tot;
inline void Add_Edge(int f, int t){
edge[++tot] = _(fst[f], t); fst[f] = tot;
edge[++tot] = _(fst[t], f); fst[t] = tot;
}
int fa[18][MAXN], dep[MAXN];
void dfs(int x, int y){
dep[x] = dep[y]+1;
fa[0][x] = y; for(register int i=1; i<18; i++) fa[i][x] = fa[i-1][fa[i-1][x]];
for(register int u=fst[x]; u; u=edge[u].nxt){
int v=edge[u].to;
if(v==y) continue;
dfs(v,x);
}
}
inline int jump(int x, int k){
for(register int i=17; ~i; i--) if(k>>i&1) x = fa[i][x];
return x;
}
inline int lca(int u, int v){
if(dep[u]<dep[v]) swap(u,v);
u = jump(u,dep[u]-dep[v]);
if(u==v) return u;
for(register int i=17; ~i; i--) if(fa[i][u]!=fa[i][v]) u = fa[i][u], v = fa[i][v];
return fa[0][u];
}
inline void move(int &x, int tar, int step){
// printf("move %d %d %d\n",x,tar,step);
int y = lca(x,tar), dis = dep[x]+dep[tar]-2*dep[y];
if(step>=dis) x = tar;
else if(step<=dep[x]-dep[y]) x = jump(x,step);
else x = jump(tar,dis-step);
// printf("%d\n",x);
}
int main(){
// freopen("2.in","r",stdin);
Read(n); Read(m);
for(register int i=1; i<=n; i++) Read(a[i].b);
for(register int i=1; i<=n; i++) Read(a[i].k), a[i].id = i, Insert(root,0,1e9,a[i]);
for(register int i=1; i<n; i++){
int f, t;
Read(f); Read(t);
f++, t++;
Add_Edge(f,t);
}
dfs(1,0);
lst = Query(root,0,1e9,1e9).id;
nowmx = Query(root,0,1e9,0).id;
while(nowmx != lst){
int head=nowpos, tail=1e9;
while(head<tail){
int mid = head+tail >> 1;
if(Query(root,0,1e9,mid).id == nowmx) head = mid+1;
else tail = mid;
}
nowmx = Query(root,0,1e9,nowpos=head).id;
q[++qcnt] = (upt){nowpos,-nowmx};
}
for(register int i=1; i<=m; i++) qcnt++, Read(q[qcnt].t), q[qcnt].opt = i;
sort(q+1,q+qcnt+1);
nowmx = Query(root,0,1e9,0).id;
for(register int i=1, now=1; i<=qcnt; i++){
move(now,nowmx,q[i].t-q[i-1].t);
if(q[i].opt<0) nowmx = -q[i].opt;
else ans[q[i].opt] = now;
// printf("%d %d %d\n",q[i].t,q[i].opt,now);
}
for(register int i=1; i<=m; i++) printf("%d\n",ans[i]-1);
return 0;
}