//第300篇博客祭QAQ
傳送門
解題思路
挺好的一道題。
首先可以觀察到,若按照水流方向建邊,則整張圖是個DAG。
- 第一步:建圖。
令水池(0號店)爲根。先用單調遞減棧求出每個圓盤下面第一個比他大的圓盤,很顯然水就往那裏流,將這兩個點之間連邊,最後0號店向棧中剩下元素連邊。 - 第二步:預處理ST表
設dp[i][j]表示從i號節點流2^j個圓盤所到達的圓盤。
設f[i][j]表示從i號節點流2^j個圓盤需要總水量的下界(開區間),即只有v>f[i][j]時,纔可以流過去。 - 第三步:查詢並得到答案
需要注意:- 開閉區間。
- 先更新剩餘流量v,再所到達的節點r。
AC代碼
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
using namespace std;
const int maxn=1e5+5;
stack<int> s;
struct Node{
int d;
long long c;
}a[maxn];
struct node{
int v,next;
long long w;
}e[maxn];
int dep[maxn],dp[maxn][35],cnt,p[maxn],n,q;
long long f[maxn][35];
void insert(int u,int v,int w){
cnt++;
e[cnt].v=v;
e[cnt].next=p[u];
e[cnt].w=w;
p[u]=cnt;
}
void dfs(int u,int fa,int deep,long long w){
dep[u]=deep;
dp[u][0]=fa;
f[u][0]=w;
for(int j=1;j<=30;j++){
if((1<<j)>=dep[u]) break;
dp[u][j]=dp[dp[u][j-1]][j-1];
f[u][j]=f[u][j-1]+f[dp[u][j-1]][j-1];
}
for(int i=p[u];i!=-1;i=e[i].next){
int v=e[i].v;
dfs(v,u,deep+1,e[i].w);
}
}
int main(){
ios::sync_with_stdio(false);
memset(p,-1,sizeof(p));
memset(f,0x3f,sizeof(f));
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>a[i].d>>a[i].c;
while(!s.empty()&&a[s.top()].d<a[i].d){
insert(i,s.top(),a[s.top()].c);
s.pop();
}
s.push(i);
}
while(!s.empty()){
insert(0,s.top(),a[s.top()].c);
s.pop();
}
dfs(0,0,1,1e10+5);
while(q--){
int r;
long long v;
cin>>r>>v;
for(int j=log2(dep[r]-1);j>=0;j--){
if(f[r][j]<v){
v-=f[r][j];
r=dp[r][j];
}
}
cout<<r<<endl;
}
return 0;
}