题意:
给出一个初始点只有1的树,权值为0,有两种操作:
1. 1. 1. 往树中加入一个节点
2.查询从某个节点起,往祖先方向能找到的最长非降子序列。要求:权值和不能超过 x x x ,并且后一个点是前一个点的祖先,且必须是最近的,权值 ≥ \geq ≥ 前一个点的祖先。
操作强制在线。
题解:
像这种往祖先方向查询的操作,可以考虑倍增法。
设 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示节点 i i i 向上找长度为 2 j 2^j 2j 的非降子序列后所处的位置
设 s u m [ i ] [ j ] sum[i][j] sum[i][j] 表示节点 i i i 向上找长度为 2 j 2^j 2j 的非降子序列后的和。
那么只需找到 d p [ i ] [ 0 ] dp[i][0] dp[i][0]即可接连求出 d p [ i ] [ j ] dp[i][j] dp[i][j] 。
要想找到第一个大于等于 i i i 的祖先,就要根据节点 i i i 的父亲 f a fa fa 来求得。
1.如果 f a fa fa的权值大于等于 i i i ,那么 d p [ i ] [ 0 ] = f a dp[i][0]=fa dp[i][0]=fa
2. 2. 2. 否则,找到 一个最大的 j j j满足 w [ d p [ f a ] [ j ] ] < w [ i ] w[dp[fa][j]]<w[i] w[dp[fa][j]]<w[i] ,然后跳到 d p [ f a ] [ j ] dp[fa][j] dp[fa][j] 继续重复操作。为什么可以直接跳呢?
假设中间存在一个大于等于 w [ i ] w[i] w[i]的位置,那么不论这个数有没有被选到序列中, w [ d p [ f a ] [ j ] ] w[dp[fa][j]] w[dp[fa][j]]都一定会大于等于这个数,那么自然也就大于等于 w [ i ] w[i] w[i] ,所以如果 w [ d p [ f a ] [ j ] ] < w [ i ] w[dp[fa][j]]<w[i] w[dp[fa][j]]<w[i],那么就可以直接跳。
代码:
#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=5e5+5;
const ll inf=0x3f3f3f3f3f3f3f3f;
int last=0;
int cnt=1;
ll w[MAXN],dp[MAXN][30],sum[MAXN][30];
void add(ll x,ll y)
{
int u=(x^last);
w[++cnt]=(y^last);
//cout<<u<<endl;
if(w[cnt]<=w[u]) dp[cnt][0]=u;
else{
for(int i=20;i>=0;i--){
if(w[cnt]>w[dp[u][i]]){
u=dp[u][i];
}
}
dp[cnt][0]=dp[u][0];
}
if(dp[cnt][0]==0) sum[cnt][0]=inf;
else sum[cnt][0]=w[dp[cnt][0]];
for(int i=1;i<=20;i++){
dp[cnt][i]=dp[dp[cnt][i-1]][i-1];
if(dp[cnt][i]==0) sum[cnt][i]=inf;
else sum[cnt][i]=sum[dp[cnt][i-1]][i-1]+sum[cnt][i-1];
}
}
int query(ll x,ll y)
{
int r=(x^last);
ll cost=(y^last)-w[r];
int ans=0;
if(cost>=0) ans++;
for(int i=20;i>=0;i--){
if(sum[r][i]<=cost){
//cout<<sum[r][i]<<" "<<cost<<endl;
ans+=(1<<i);
cost-=sum[r][i];
r=dp[r][i];
}
}
return ans;
}
int main()
{
int n;
scanf("%d",&n);
w[0]=inf;
w[1]=0;
for(int i=0;i<=20;i++){
sum[1][i]=inf;
}
while(n--){
ll op,x,y;
scanf("%lld%lld%lld",&op,&x,&y);
if(op==1){
add(x,y);
}
else{
last=query(x,y);
printf("%d\n",last);
}
}
}