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;
}
posted @ 2021-06-24 16:44  oisdoaiu  阅读(27)  评论(0编辑  收藏  举报