题目
原题地址
解说
首先发现乘的时候 系数不会为负,所以能得到一个关键条件:变化后的战斗力随变化前的战斗力大小单调
所以我们考虑倍增
设hp[x][i]是从x开始一路攻克\(2^i\)个城池所需要最小的初始生命值
设trans[x][i][0/1]是攻克了\(2^i\)个城池后攻击力的变化量,0表示乘,1表示加,先乘后加
注意乘的系数初始化成1
然后就可以倍增了
然而空间大小恶意卡倍增
但是我们这个倍增可以换成三进制的
就是把定义里的\(2^i\)都换成\(3^i\)
于是\(log_3300000=10\),空间就变成了原来的一半
需要注意的一点是,最后在跳倍增的时候,同一个长度可以跳两次(因为是三进制嘛),循环的时候稍微注意一下
代码
#include
#define pa pair
#define CLR(a,x) memset(a,x,sizeof(a))
#define MP make_pair
using namespace std;
typedef long long ll;
const int maxn=3e5+5;
inline char gc(){
return getchar();
static const int maxs=1<<16;static char buf[maxs],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++;
}
inline ll rd(){
ll x=0;char c=gc();bool neg=0;
while(c<'0'||c>'9'){if(c=='-') neg=1;c=gc();}
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=gc();
return neg?(~x+1):x;
}
int N,M,fa[maxn][11];
ll hp[maxn][11],trans[maxn][11][2];
int ans1[maxn],ans2[maxn];
int pw3[11];
int main(){
//freopen("","r",stdin);
int i,j,k;
pw3[0]=1;for(i=1;i<=10;i++) pw3[i]=pw3[i-1]*3;
N=rd(),M=rd();
for(i=1;i<=N;i++) hp[i][0]=rd();
fa[1][0]=N+1;
for(i=2;i<=N;i++){
fa[i][0]=rd();
ll x=rd(),y=rd();
trans[i][0][0]=1;
trans[i][0][!x]=y;
for(j=0;j<10;j++){
int f=fa[i][j],ff=fa[f][j];
if(!f||!ff||!fa[ff][j]) break;
fa[i][j+1]=fa[ff][j];
ll hp1=max(hp[f][j],(ll)ceil(1.0*(hp[ff][j]-trans[f][j][1])/trans[f][j][0]));
hp[i][j+1]=max(hp[i][j],(ll)ceil(1.0*(hp1-trans[i][j][1])/trans[i][j][0]));
trans[i][j+1][1]=trans[i][j][1]*trans[f][j][0]+trans[f][j][1];
trans[i][j+1][0]=trans[i][j][0]*trans[f][j][0];
trans[i][j+1][1]=trans[i][j+1][1]*trans[ff][j][0]+trans[ff][j][1];
trans[i][j+1][0]=trans[i][j+1][0]*trans[ff][j][0];
}
}
for(i=1;i<=M;i++){
ll s=rd();int x=rd(),n=0;
for(j=10;j>=0&&x!=-1;j--){
if(fa[x][j]&&hp[x][j]<=s){
s=s*trans[x][j][0]+trans[x][j][1];
x=fa[x][j];
n+=pw3[j];j++;
}
}
if(x!=-1) ans1[x]++;
ans2[i]=n;
}
for(i=1;i<=N;i++)
printf("%d\n",ans1[i]);
for(i=1;i<=M;i++)
printf("%d\n",ans2[i]);
return 0;
}
幸甚至哉,歌以咏志。