D. Tree
time limit per test 2seconds
memory limit per test 512megabytes
You are given a node of the tree withindex 1 and with weight 0. Let cnt be the numberof nodes in the tree at any instant (initially, cnt is set to 1). Support Q queries offollowing two types:
· Add
a new node (index cnt + 1)
with weight W
and add edgebetween node R
and this node.
· Output
the maximum length of sequence of nodes which
1. starts with R.
2. Every node in the sequence is an ancestor of itspredecessor.
3. Sum of weight of nodes in sequence does not exceed X.
4. For some nodes i, j that areconsecutive in the sequence if i is an ancestorof j then w[i] ≥ w[j] and thereshould not exist a node k on simple path from i to j such that w[k] ≥ w[j]
The tree is rooted at node 1 at any instant.
Note that thequeries are given in a modified way.
Input
First line containing the number ofqueries Q (1 ≤ Q ≤ 400000).
Let last be the answerfor previous query of type 2 (initially last equals 0).
Each of the next Q lines containsa query of following form:
· 1
p q (1 ≤ p, q ≤ 1018):
This is queryof first type where
and
. It is guaranteed that 1 ≤ R ≤ cnt
and 0 ≤ W ≤ 109.
· 2
p q (1 ≤ p, q ≤ 1018):
This is queryof second type where and
. It is guaranteed that
1 ≤ R ≤ cnt
and 0 ≤ X ≤ 1015.
denotes bitwise XOR of
a
and b.
It is guaranteed that at least one queryof type 2 exists.
Output
Output the answer to each query of second type inseparate line.
【题意】
有一棵树,书上每个点都有一个权值,一开始只有根节点,且权值为0。然后有两种操作:
一种是新加上一个节点连在R后面,且权值为W;
第二种是从一个点R开始往祖先走,每次走到第一个权值大于等于自身的节点,问走过的节点权值和不超过X,最多能经过几个点。
【思路】
对于往祖先找符合条件的点,暴力方法便是一个一个往祖先走,但是我们可以用倍增的思想来优化。
我们用fa[u][i]表示权值大于等于u的第2i个祖先,每次加点时先处理出fa[u][0],然后就能根据祖先节点推出fa[u][i]
对于fa[u][0],如何其依附的点R权值大于等于它,那么fa[u][0]即为R,否则我们应该从R开始走,i从大的往小的枚举(走2i步),如果满足w[fa[R][i]] < w[u],说明权值大于u的点还在上面,跳上去更新R代表的点,继续枚举,最后fa[u][0]=fa[R][0];
对于查询操作,我们需要sum[u][i]表示从u点跳2i个点(不包括u)的权值和,然后查询时,先判断总权值X是否大于等于u的权值,是的话X-=w[u],然后同上,i从大的开始枚举如果sum[u][i]<=X就往祖先走,并且X-=sum[u][i],以此类推。
#include <cstdio>
#include <cmath>
#include <set>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)
typedef long long ll;
const int maxn = 400005;
const ll mod = 1e9+7;
const ll INF = 1e18;
const double eps = 1e-9;
int q,op,cnt;
ll a,b,last;
ll w[maxn],sum[maxn][25];
int fa[maxn][25];
void add(int u,int val)
{
w[++cnt]=val;
if(w[cnt]<=w[u]) fa[cnt][0]=u;
else
{
for(int i=20;i>=0;i--)
{
if(w[fa[u][i]]<w[cnt]) u=fa[u][i];
}
fa[cnt][0]=fa[u][0];
}
if(fa[cnt][0]==0) sum[cnt][0]=INF;
else sum[cnt][0]=w[fa[cnt][0]];
for(int i=1;i<=20;i++)
{
fa[cnt][i]=fa[fa[cnt][i-1]][i-1];
if(fa[cnt][i]==0) sum[cnt][i]=INF;
else sum[cnt][i]=sum[cnt][i-1]+sum[fa[cnt][i-1]][i-1];
}
}
ll query(int u,ll val)
{
if(w[u]>val) return 0;
val-=w[u];
ll ans=1;
for(int i=20;i>=0;i--)
{
if(val>=sum[u][i])
{
val-=sum[u][i];
ans+=(1<<i);
u=fa[u][i];
}
}
return ans;
}
int main()
{
w[0]=INF;
w[1]=0;
last=0;
cnt=1;
mst(sum[1],0x3f);
scanf("%d",&q);
while(q--)
{
scanf("%d%lld%lld",&op,&a,&b);
a^=last;
b^=last;
if(op==1) add(a,b);
else printf("%lld\n",last=query(a,b));
}
}