Luogu-P3203 Bounce Sheep

topic

topic link

meaning of the title

It is said that this problem uses a data structure called LCT, but I don't. . .

There are n spring devices in a row, starting from the i one can jump back k [ i ] step.

  • Modify: Modify the elasticity of the spring at a certain position.
  • Query: Ask how many times it bounces from a certain position.

answer

Blocking must first start with violence:
we record where we start from any point and where we can jump next time. In this case, every time we ask, we only need to go down this chain. Obviously, the most The bad time complexity is O ( n 2 ) , the time complexity of the modification is O ( 1 )

Optimization:
Let's optimize using chunking, where we chunk n springs on a line and record two properties for each spring: s u m [ i ] and n x t b [ i ]

in s u m [ i ] means from i The number of nodes that the spring has passed through in this block, n x t b [ i ] means from i The spring starts, bounces to the number of the first spring in the next block, and the bounce is set to -1.

In this case, we only need the following code when asking.

int now = x;
while(x != -1){
    ans += sum[now];
    now = nxtb[now];
}

For preprocessing, we have to calculate backwards, because the previous sum uses the latter sum.
See the code for details on preprocessing and modification.

code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 200007;
#define pr(x) cout<<#x<<":"<<x<<endl
int Base = 450;
int nxtb[maxn];
int val[maxn];
int sum[maxn];
int n,m,op,x,y;
inline void read(int &x){
    scanf(" %d",&x);
}
int main(){
    read(n);
    Base = (int) sqrt(n+0.5);
    for(int i = 1;i <= n;++i){
        read(val[i]);
    }

    for(int i = n;i >= 1;--i){
        int j = val[i] + i;
        int bl = i / Base;
        int br = j / Base;
        if(j > n){
            nxtb[i] = -1;
            sum[i] = 1;
        }
        else if(br == bl){
            //属于同一个块
            nxtb[i] = nxtb[j];
            sum[i] = sum[j]+1;
        }
        else{
            //不属于同一个块
            nxtb[i] = j;
            sum[i] = 1;
        }
    }

    read(m);
    while(m--){
        read(op);
        if(op == 1){
            //询问
            read(x);
            x++;
            int ans = 0;
            int now = x;
            while(now != -1){
                ans += sum[now];
                now = nxtb[now];
            }
            printf("%d\n",ans);
        }
        else{
            //修改
            read(x);read(y);
            x++;
            val[x] = y;
            int j = x + y;
            int bl = x / Base;
            int br = j / Base;
            if(j > n){
                sum[x] = 1;
                nxtb[x] = -1;
            }
            else if(bl == br){
                //属于用一个块
                sum[x] = sum[j] + 1;
                nxtb[x] = nxtb[j];
            }
            else{
                //不属于同一个块
                sum[x] = 1;
                nxtb[x] = j;
            }
            for(int i = x-1;i >= max(1,bl*Base);--i){
                //更新与x属于同一块的可能被x影响的弹簧。
                j = i + val[i];
                br = j / Base;
                if(br == bl){
                    sum[i] = sum[j] + 1;
                    nxtb[i] = nxtb[j];
                }
            }
        }
    }
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325762337&siteId=291194637