• 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 }
  • 相关阅读:
    学习进度条博客2
    软件工程第二周开课博客
    switch is not a valid resource name (reserved Java keyword)
    返回一个整型数组中最大子数组的和(2)
    返回一个整型数组中最大子数组的和(1)
    二级联动
    微信小程序连接Java后台
    异步数据加载和更新(来源官网)
    动态数据+时间坐标轴(部分注释)
    Echarts-样式简介
  • 原文地址:https://www.cnblogs.com/Ressed/p/10022977.html
Copyright © 2020-2023  润新知