标签:out math size 删除 getc names pac 添加 span
普及组难度树上倍增题。
我们只需要做到以下内容(在线),就能完成本题:
如果能做到以上三点,那么对于操作 \(1\) 就添加,对于操作 \(2\) 就不停地查询根,如果能买黄金就买,买完以后删除,然后计算即可。
删除很难,考虑给已删除的点打一个标记。于是查询的时候,倍增往上跳到第一个没有打标记的点,它一定就是要查询的根。所以在添加点的时候就可以把倍增预处理好。
记得 fflush(stdout)
。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(x) memset(x,0,sizeof(x))
//const ll inf=1000000000000000000;
const int N=300005;
int q;
ll a[N],c[N];
int lg[N];
bool used[N];
int fath[N][21],depth[N];
void dfs(int u,int fa)
{
depth[u]=depth[fa]+1;
fath[u][0]=fa;
for (int i=1;i<=lg[depth[u]];i++)
{
fath[u][i]=fath[fath[u][i-1]][i-1];
}
}
inline int read()
{
char C=getchar();
int F=1,ANS=0;
while (C<‘0‘||C>‘9‘)
{
if (C==‘-‘) F=-1;
C=getchar();
}
while (C>=‘0‘&&C<=‘9‘)
{
ANS=ANS*10+C-‘0‘;
C=getchar();
}
return F*ANS;
}
int ask(int x)
{
for (int i=lg[depth[x]];i>=0;i--)
{
if (used[fath[x][i]]==0)
{
x=fath[x][i];
}
}
return x;
}
int main()
{
q=read(),a[0]=read(),c[0]=read();
for (int i=1;i<=300000;i++)
{
lg[i]=lg[i-1]+(1<<lg[i-1]==i);
}
for (int i=1;i<=300000;i++)
{
lg[i]--;
}
for (int i=1;i<=q;i++)
{
int tp=read();
if (tp==1)
{
int p=read();
a[i]=read(),c[i]=read();
dfs(i,p);
}
else
{
ll v=read(),w=read();
ll ans=0;
ll ww=w;
while (1)
{
int r=ask(v);
if (used[r]) break;
if (w>=a[r])
{
used[r]=1;
w-=a[r];
ans+=a[r]*c[r];
a[r]=0;
}
else
{
a[r]-=w;
ans+=w*c[r];
w=0;
break;
}
}
printf("%lld %lld\n",ww-w,ans);
fflush(stdout);
}
}
return 0;
}
标签:out math size 删除 getc names pac 添加 span
原文地址:https://www.cnblogs.com/irty/p/14876705.html