codeforces 13EE. Holes(分塊&動態樹)

E. Holes
time limit per test
1 second
memory limit per test
64 megabytes
input
standard input
output
standard output

Little Petya likes to play a lot. Most of all he likes to play a game «Holes». This is a game for one person with following rules:c++

There are N holes located in a single row and numbered from left to right with numbers from 1 to N. Each hole has it's own power (hole number i has the power ai). If you throw a ball into hole i it will immediately jump to hole i + ai, then it will jump out of it and so on. If there is no hole with such number, the ball will just jump out of the row. On each of the M moves the player can perform one of two actions:ide

  • Set the power of the hole a to value b.
  • Throw a ball into the hole a and count the number of jumps of a ball before it jump out of the row and also write down the number of the hole from which it jumped out just before leaving the row.

Petya is not good at math, so, as you have already guessed, you are to perform all computations.post

Input

The first line contains two integers N and M (1 ≤ N ≤ 1051 ≤ M ≤ 105) — the number of holes in a row and the number of moves. The second line contains N positive integers not exceeding N — initial values of holes power. The following M lines describe moves made by Petya. Each of these line can be one of the two types:ui

  • 0 a b
  • 1 a
Type  0 means that it is required to set the power of hole  a to  b, and type  1 means that it is required to throw a ball into the  a-th hole. Numbers  a and  b are positive integers do not exceeding  N.
Output

For each move of the type 1 output two space-separated numbers on a separate line — the number of the last hole the ball visited before leaving the row and the number of jumps it made.spa

Sample test(s)
input
8 5
1 1 1 1 1 2 8 2
1 1
0 1 3
1 1
0 3 4
1 2
output
8 7
8 5
7 3
題意:
給你n個編號1到N的洞(N<=1e5)。

每個洞有個能量值po[i]。指針

當你在i號洞裏放一個球時.這個球會彈到i+po[i]號洞內。code

而後彈到i+po[i]+po[i+po[i]]。。orm

。。也就是說球每到一個洞i就會彈到i+po[i]號洞內。blog

現在有兩種操做。ip

1.0 a b。把a號洞的po改爲b
2.1 a。

詢問當把球放到a號洞內時。它是從幾號洞彈出界的。和它一共彈了幾回。


思路:
假設題目沒有改動操做。這題就會很是easy。

咱們僅僅需要把每個洞的出界點和彈跳數預處理出來就可以了。現在關鍵是怎麼處理改動操做。假設仍是依照上述預處理方式確定時間複雜度下不來。

因此咱們要想辦法使每次改動操做更新儘可能少的信息。因而可以想到分塊處理。就是把整個序列分紅sqrt(N)塊。序列中每個節點記錄next[i]表示i結點要跳到下個塊的位置。ed[i]表示放到i號洞時的出界位置。st[i]表示。

i跳到下個塊需要的步數。這樣預處理後每次改動操做僅僅會影響同塊內且標號比當前小的位置的信息。

因此最多改動sqrt(n)個位置的信息。對於每次查詢操做。由於結點指針僅僅會指向不一樣的塊因此僅僅需要順着指針統計一遍就行了。最多跳sqrt(n)次。

總時間發雜度O(M*sqrt(N))在可以接受的範圍內。

具體見代碼:
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=100010;
typedef long long ll;
int st[maxn],next[maxn],ed[maxn],po[maxn];
int block,n,m,ans,ansp;
void update(int x,int y)
{
    if(y>n)
        ed[x]=x,st[x]=1,next[x]=y;
    else
    {
        ed[x]=ed[y];//ed[x]爲從x處放球的終點
        if(x/block==y/block)
            next[x]=next[y],st[x]=st[y]+1;//next[i]表示i跳到另外的塊的位置
        else
            next[x]=y,st[x]=1;
    }
}
void qu(int x)
{
    ans=0;
    while(1)
    {
        ans+=st[x];
        if(next[x]>n)
        {
            ansp=ed[x];
            break;
        }
        x=next[x];
    }
}
int main()
{
    int i,cmd,a,b;

    while(~scanf("%d%d",&n,&m))
    {
        block=ceil(sqrt(1.0*n));
        for(i=1;i<=n;i++)
            scanf("%d",&po[i]);
        for(i=n;i>=1;i--)
            update(i,i+po[i]);
        while(m--)
        {
            scanf("%d%d",&cmd,&a);
            if(cmd)
            {
                qu(a);
                printf("%d %d\n",ansp,ans);
            }
            else
            {
                scanf("%d",&po[a]);
                b=(a/block)*block;
                b=max(b,1);
                for(i=a;i>=b;i--)
                    update(i,i+po[i]);
            }
        }
    }
    return 0;
}
相關文章
相關標籤/搜索