21.6.13 t2
阿新 • • 發佈:2021-06-24
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; }