luogu3621 城池攻占 (倍增)

好像所有人都写的左偏树 但我不会啊233

首先发现乘的时候 系数不会为负,所以能得到一个关键条件:变化后的战斗力随变化前的战斗力大小单调

所以我们考虑倍增

设hp[x][i]是从x开始一路攻克$2^i$个城池所需要最小的初始生命值

设trans[x][i][0/1]是攻克了$2^i$个城池后攻击力的变化量,0表示乘,1表示加,先乘后加

然后就可以倍增了

 1 #include<bits/stdc++.h>
 2 #define pa pair<ll,ll>
 3 #define CLR(a,x) memset(a,x,sizeof(a))
 4 #define MP make_pair
 5 using namespace std;
 6 typedef long long ll;
 7 const int maxn=3e5+5;
 8 
 9 inline char gc(){
10     return getchar();
11     static const int maxs=1<<16;static char buf[maxs],*p1=buf,*p2=buf;
12     return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++;
13 }
14 inline ll rd(){
15     ll x=0;char c=gc();bool neg=0;
16     while(c<'0'||c>'9'){if(c=='-') neg=1;c=gc();}
17     while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=gc();
18     return neg?(~x+1):x;
19 }
20 
21 int N,M,fa[maxn][21];
22 ll hp[maxn][21],trans[maxn][21][2];
23 int ans1[maxn],ans2[maxn];
24 
25 int main(){
26     //freopen("","r",stdin);
27     int i,j,k;
28     N=rd(),M=rd();
29     for(i=1;i<=N;i++) hp[i][0]=rd();
30     fa[1][0]=N+1;
31     for(i=2;i<=N;i++){
32         fa[i][0]=rd();
33         ll x=rd(),y=rd();
34         trans[i][0][0]=1;
35         trans[i][0][!x]=y;
36         for(j=0;fa[i][j]&&fa[fa[i][j]][j];j++){
37             fa[i][j+1]=fa[fa[i][j]][j];
38             hp[i][j+1]=max(hp[i][j],(ll)ceil(1.0*(hp[fa[i][j]][j]-trans[i][j][1])/trans[i][j][0]));
39             trans[i][j+1][1]=trans[i][j][1]*trans[fa[i][j]][j][0]+trans[fa[i][j]][j][1];
40             trans[i][j+1][0]=trans[i][j][0]*trans[fa[i][j]][j][0];
41         }
42     }
43     for(i=1;i<=M;i++){
44         ll s=rd();int x=rd(),n=0;
45         for(j=20;j>=0&&x!=-1;j--){
46             if(fa[x][j]&&hp[x][j]<=s){
47                 s=s*trans[x][j][0]+trans[x][j][1];
48                 x=fa[x][j];
49                 n+=1<<j;
50             }
51         }
52         if(x!=-1) ans1[x]++;
53         ans2[i]=n;
54     }
55     for(i=1;i<=N;i++)
56         printf("%d
",ans1[i]);
57     for(i=1;i<=M;i++)
58         printf("%d
",ans2[i]);
59     
60     return 0;
61 }
好好分析空间啊kora!

然而空间大小恶意卡倍增

但是我们这个倍增可以换成三进制的2333

就是把定义里的$2^i$都换成$3^i$

于是$log_3300000=10$,空间就变成了原来的一半

需要注意的一点是,最后在跳倍增的时候,同一个长度可以跳两次(因为是三进制嘛),循环的时候稍微注意一下

 1 #include<bits/stdc++.h>
 2 #define pa pair<ll,ll>
 3 #define CLR(a,x) memset(a,x,sizeof(a))
 4 #define MP make_pair
 5 using namespace std;
 6 typedef long long ll;
 7 const int maxn=3e5+5;
 8 
 9 inline char gc(){
10     return getchar();
11     static const int maxs=1<<16;static char buf[maxs],*p1=buf,*p2=buf;
12     return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++;
13 }
14 inline ll rd(){
15     ll x=0;char c=gc();bool neg=0;
16     while(c<'0'||c>'9'){if(c=='-') neg=1;c=gc();}
17     while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=gc();
18     return neg?(~x+1):x;
19 }
20 
21 int N,M,fa[maxn][11];
22 ll hp[maxn][11],trans[maxn][11][2];
23 int ans1[maxn],ans2[maxn];
24 int pw3[11];
25 
26 int main(){
27     //freopen("","r",stdin);
28     int i,j,k;
29     pw3[0]=1;for(i=1;i<=10;i++) pw3[i]=pw3[i-1]*3;
30     N=rd(),M=rd();
31     for(i=1;i<=N;i++) hp[i][0]=rd();
32     fa[1][0]=N+1;
33     for(i=2;i<=N;i++){
34         fa[i][0]=rd();
35         ll x=rd(),y=rd();
36         trans[i][0][0]=1;
37         trans[i][0][!x]=y;
38         for(j=0;j<10;j++){
39             int f=fa[i][j],ff=fa[f][j];
40             if(!f||!ff||!fa[ff][j]) break;
41             fa[i][j+1]=fa[ff][j];
42             ll hp1=max(hp[f][j],(ll)ceil(1.0*(hp[ff][j]-trans[f][j][1])/trans[f][j][0]));
43             hp[i][j+1]=max(hp[i][j],(ll)ceil(1.0*(hp1-trans[i][j][1])/trans[i][j][0]));
44             trans[i][j+1][1]=trans[i][j][1]*trans[f][j][0]+trans[f][j][1];
45             trans[i][j+1][0]=trans[i][j][0]*trans[f][j][0];
46             trans[i][j+1][1]=trans[i][j+1][1]*trans[ff][j][0]+trans[ff][j][1];
47             trans[i][j+1][0]=trans[i][j+1][0]*trans[ff][j][0];
48         }
49     }
50     for(i=1;i<=M;i++){
51         ll s=rd();int x=rd(),n=0;
52         for(j=10;j>=0&&x!=-1;j--){
53             if(fa[x][j]&&hp[x][j]<=s){
54                 s=s*trans[x][j][0]+trans[x][j][1];
55                 x=fa[x][j];
56                 n+=pw3[j];j++;
57             }
58         }
59         if(x!=-1) ans1[x]++;
60         ans2[i]=n;
61     }
62     for(i=1;i<=N;i++)
63         printf("%d
",ans1[i]);
64     for(i=1;i<=M;i++)
65         printf("%d
",ans2[i]);
66     
67     return 0;
68 }
原文地址:https://www.cnblogs.com/Ressed/p/10022977.html