题目描述
小 R 种了一棵苹果树,这棵树上有 n 个节点(标号从 0 到 n-1),有 n-1 条树枝连接这n 个节点,这 n 个节点相互连通。每条树枝的长度为 1。
苹果树上的每一个节点上生长着一个苹果,这个苹果散发着香味。在 0 时刻,第 i 个节点的苹果散发香味的浓郁度为 s[i],以后每过一个单位时间,香味的浓郁度就会增加 a[i]。
苹果树上还有一只蚂蚁,在 0 时刻时,这只蚂蚁在 0 号节点,在第 i 时刻,它会朝着第 i 时刻时香味最浓郁的节点方向走 1 个单位长度。(如果两个节点的浓郁度相同,则标号较大的节点被认为是香味更浓郁的)。如果在第 i 时刻,蚂蚁所处的位置已经是香味最浓郁的节点了,那么它会选择在原地休息。
给出 n ,和 s[i] ,a[i] ,再给出 m ,和 m 个询问,每一个询问有个 t ,表示询问在时刻 t ,蚂蚁爬到了哪里。
题目解析
好吧,这是某场模拟赛的第一题,网上也找不到出处。开考前20分钟就想到了正解,暴力模拟嘛,结果离考试结束一个小时才发现
t
的数据范围看错了,以为来不及改了,就拿了个50分,考完再思考这道题时发现10钟就可以改出来,哭。
正解是维护下凸包,我的写法没那么复杂,直接用链表+优先队列找出每一个最香点的时间段,再用倍增爬树就行了。
我先按时刻0的优先级排序,找到时刻0的最优解(因为存在两个
然后在队列不为空的情况下,每次取出队首元素,对所有与他时间相同的元素进行超越操作,若两者都已被删除,忽略此次操作,否则删掉被超越的元素,再将超越的元素与他前面的元素再次建立关系,直到队列为空或队首元素时间不等。记录当前的时间和最香的节点,可以保证至多有
n
次插入和取出,只有
然后离线每一个询问,排序,然后再树上倍增爬到当前询问的时间或是最香的节点改变的时候,至多爬
m
次,时间复杂度
至于为什么可以建立链表而只有相邻两个元素建立关系,可以认为是赛跑,再以起点排序后,若
a
想超越
这样看起来细节有点多,但是如果写好计算超越时间的函数其实还好。
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
#define MAXN 100000
#define MAXM 100000
#define INF 0x3f3f3f3f
typedef long long int LL;
template<class T>
void Read(T &x){
x=0;char c=getchar();bool flag=0;
while(c<'0'||'9'<c){if(c=='-')flag=1;c=getchar();}
while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
if(flag)x=-x;
}
struct node{
int v;
node *nxt;
}*adj[MAXN+10],Edges[MAXN*2+10],*New=Edges;
void addedges(int u,int v){
node *p=++New;
p->v=v;
p->nxt=adj[u];
adj[u]=p;
p=++New;
p->v=u;
p->nxt=adj[v];
adj[v]=p;
}
int n,m;
int head;
int L[MAXN+10],R[MAXN+10];
bool die[MAXN+10];
int t[MAXN+10],tgt[MAXN+10];
int ans[MAXM+10];
int maxlog;
int fa[MAXN+10],dep[MAXN+10];
void dfs(int x,int f){
fa[x]=f,dep[x]=dep[f]+1;
for(node *p=adj[x];p!=NULL;p=p->nxt)
if(p->v!=f)dfs(p->v,x);
}
const int MAXLOG = 17;
int dp[MAXN+10][MAXLOG+2];
void init(){
memset(dp,0,sizeof(dp));
memset(fa,0,sizeof(fa));
memset(dep,0,sizeof(dep));
maxlog=log(n)/log(2);
dfs(1,0);
for(int i=1;i<=n;++i)
dp[i][0]=fa[i];
for(int len=1;len<=maxlog;++len)
for(int i=1;i<=n;++i)dp[i][len]=dp[dp[i][len-1]][len-1];
}
int lca(int a,int b){
if(dep[a]<dep[b])swap(a,b);
for(int len=maxlog;len>=0;--len)
if(dep[dp[a][len]]>=dep[b])a=dp[a][len];
if(a==b)return a;
for(int len=maxlog;len>=0;--len)
if(dp[a][len]!=dp[b][len])a=dp[a][len],b=dp[b][len];
return fa[a];
}
int mov(int x,int v,int w){
int rt=lca(x,v);
int pos;
if(dep[x]+dep[v]-dep[rt]-dep[rt]<=w)return v;
else if(dep[x]-dep[rt]>=w)pos=x;
else pos=v,w=dep[v]-dep[rt]-(w-(dep[x]-dep[rt]));
int len=0;
while(w){
if(w&1)pos=dp[pos][len];
w>>=1;
++len;
}
return pos;
}
struct point{
int pos;
LL t;
point(){}
point(int a,LL b):pos(a),t(b){}
bool operator < (const point &x)const{
return t>x.t;
}
};
priority_queue<point>que;
struct Goal{
int id;
LL w,a;
}A[MAXN+10];
bool cmp1(const Goal &x,const Goal &y){
if(x.w!=y.w)return x.w>y.w;
else return x.id>y.id;
}
bool cmp2(const Goal &x,const Goal &y){
if(x.w!=y.w)return x.w>y.w;
else if(x.a!=y.a)return x.a>y.a;
else return x.id>y.id;
}
struct Q{
int t,id;
}B[MAXM+10];
bool cmpq(const Q &x,const Q &y){
return x.t<y.t;
}
LL Cal(int x,int y){
if(A[x].a>=A[y].a)return -1;
else{
LL tmp=(A[x].w-A[y].w)/(A[y].a-A[x].a);
if(tmp>1e9)return -1;
LL res=(A[x].w-A[y].w)%(A[y].a-A[x].a);
if(res||A[x].id>A[y].id)return tmp+1;
else return tmp;
}
}
int main(){
//freopen("ant.in","r",stdin);
//freopen("ant.out","w",stdout);
Read(n),Read(m);
for(int i=1;i<=n;++i)Read(A[i].w);
for(int i=1;i<=n;++i)Read(A[i].a);
for(int i=1;i<=n;++i)A[i].id=i;
int a,b;
for(int i=1;i<n;++i){
Read(a),Read(b);
++a,++b;
addedges(a,b);
}
sort(A+1,A+n+1,cmp1);
t[0]=0,tgt[0]=A[1].id;
sort(A+1,A+n+1,cmp2);
memset(die,0,sizeof(die));
while(!que.empty())que.pop();
head=1;
L[1]=0;
int last=1;
for(int i=2;i<=n;++i){
if(A[i].w==A[i-1].w){
die[i]=true;
continue;
}
L[i]=last,R[last]=i,last=i;
}
R[last]=0;
LL tmp;
for(int i=head;R[i];){
tmp=Cal(i,R[i]);
if(tmp==-1){
die[R[i]]=true;
L[R[R[i]]]=i,R[i]=R[R[i]];
}
else que.push(point(i,tmp)),i=R[i];
}
int cnt=0;
while(!que.empty()){
t[++cnt]=que.top().t;
while(!que.empty()&&que.top().t==t[cnt]){
tmp=que.top().pos;
if(!die[tmp]&&!die[R[tmp]]){
if(L[tmp]==0)head=R[tmp];
R[L[tmp]]=R[tmp];
L[R[tmp]]=L[tmp];
die[tmp]=true;
a=L[tmp];
while(a&&R[a]){
tmp=Cal(a,R[a]);
if(tmp==-1){
die[R[a]]=true;
L[R[R[a]]]=a,R[a]=R[R[a]];
}
else{
que.push(point(a,tmp));
break;
}
}
}
que.pop();
}
tgt[cnt]=A[head].id;
}
init();
for(int i=1;i<=m;++i){
Read(B[i].t);
B[i].id=i;
}
sort(B+1,B+m+1,cmpq);
tmp=0;
int nowt=0,nowp=1;
for(int i=1;i<=m;++i){
while(tmp<cnt&&t[tmp+1]<=B[i].t){
nowp=mov(nowp,tgt[tmp],t[tmp+1]-nowt);
nowt=t[tmp+1],++tmp;
}
nowp=mov(nowp,tgt[tmp],B[i].t-nowt);
nowt=B[i].t;
ans[B[i].id]=nowp-1;
}
for(int i=1;i<=m;++i)
printf("%d\n",ans[i]);
//fclose(stdin);
//fclose(stdout);
}
/*
5 10
0 3 1 3 3
3 2 2 2 1
0 1
0 2
1 3
1 4
0 1 2 3 4 5 6 7 8 9
*/