米缸

Description

  數據範圍:\(r,c<=2000,m<=5000,1<=M_{ij},c\)(操做中的)\(,k<=10^9\)ios

  

Solution

  形式化一下這個移動的過程,考慮若是沒有修改,那麼對於第\(x\)列的第\(i\)行,咱們能夠預處理出它\(move\)一步以後會在第\(nxt(x)\)列哪一行,具體一點就是咱們能夠對於每一列預處理出一個長度爲\(r\)的數組,記爲\(change[x][i]\),有了這個數組以後,咱們從\(change[1]\)合併到\(change[c]\)就能夠獲得一個新的數組\(change1\),其中\(change1[i]\)表示從第\(1\)列的第\(i\)\(move\)到第\(c\)列以後在哪一行c++

​  記當前所在位置爲\((nowx,nowy)\),考慮詢問,由於列數\(c\)比較小,因此對於一次\(move\ k\)操做,咱們能夠先暴力將當前的列跳到第\(1\)列(若是有那麼屢次的話),這須要\(c-nowy+1\)步,而後剩下\(k-(c-nowy+1)\)步咱們能夠先利用\(change1\)數組一圈一圈地跳(也就是\(c\)\(c\)步跳),具體的話就是能夠實現一個相似快速冪同樣的東西,計算數組\(\{1,2,3,4,...,r\}\)在連續被\(change1\)做用了\(x\)次以後會變成什麼(記爲。。\(change1^{x}\)好了),而後跳完那麼多圈以後仍是在第\(1\)列,因此這個時候的位置是\((change1^x[nowx'],nowy)\),這裏的\(nowx'\)是暴力跳到第\(1\)列以後的所在行數,而後剩下\((k-(c-nowy+1))\%c\)步也是直接暴力跳就行了數組

  如今考慮有修改,瓶頸在於要從新計算\(change1\),可是考慮一次修改對於\(change\)數組的影響,若是說修改的地方是\((x,y)\),那麼只會影響到\(change[nxt(x)]\)這一個數組的值ui

  因此咱們能夠考慮將全部的\(change[i]\)丟進線段樹做爲線段樹的底層節點維護的信息,這樣\(change1\)就是線段樹根節點處的值了,對於一次修改直接從新算一遍\(change[nxt(x)]\),而後將線段樹中\(nxt(x)\)這個位置的值更新一下便可spa

  

  mark:想清楚一次修改的影響code

  

Code

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=2010;
int a[N][N];
int n,m,q,nowx,nowy;
struct Data{
    int p[N];
    void init(){for (int i=1;i<=n;++i) p[i]=i;}
    friend Data operator + (Data x,Data y){
        for (int i=1;i<=n;++i) x.p[i]=y.p[x.p[i]];
        return x;
    }
}change[N];
namespace Seg{/*{{{*/
    const int N=::N*4;
    int ch[N][2];
    Data info[N];
    int n,tot;
    void pushup(int x){info[x]=info[ch[x][0]]+info[ch[x][1]];}
    void _build(int x,int l,int r){
        if (l==r){info[x]=change[l];return;}
        int mid=l+r>>1;
        ch[x][0]=++tot; _build(ch[x][0],l,mid);
        ch[x][1]=++tot; _build(ch[x][1],mid+1,r);
        pushup(x);
    }
    void build(int _n){n=_n; tot=1;_build(1,1,n);}
    void _update(int x,int d,int lx,int rx){
        if (lx==rx){
            info[x]=change[lx]; return;
        }
        int mid=lx+rx>>1;
        if (d<=mid) _update(ch[x][0],d,lx,mid);
        else _update(ch[x][1],d,mid+1,rx);
        pushup(x);
    }
    void update(int d){_update(1,d,1,n);}
}/*}}}*/
int X(int x){x=(x+n)%n;return x==0?n:x;}
int Y(int y){y=(y+m)%m;return y==0?m:y;}
int work(int x,int y){
    int nwy=Y(y+1),pre=X(x-1),nxt=X(x+1);
    int ret=x;
    if (a[pre][nwy]>a[ret][nwy]) ret=pre;
    if (a[nxt][nwy]>a[ret][nwy]) ret=nxt;
    return ret;
}
void prework(){
    int pre,nxt,tmp,nwy;
    for (int x=1;x<=n;++x)
        for (int y=1;y<=m;++y)
            change[y].p[x]=work(x,y);
    Seg::build(m);
}
void modify(int y){
    for (int i=1;i<=n;++i)
        change[y].p[i]=work(i,y);
    Seg::update(y);
}
void force_move(int &x,int &y,int tm){
    for (int i=1;i<=tm;++i)
        x=change[y].p[x],y=Y(y+1);
}
Data ksm(Data &x,int y){
    Data ret,base=x;
    ret.init();
    for (;y;y>>=1,base=base+base)
        if (y&1) ret=ret+base;
    return ret;
}
void solve(int tm){
    int tm1=min(tm,m-nowy+1);
    Data tmp;
    force_move(nowx,nowy,tm1);
    tmp=ksm(Seg::info[1],(tm-tm1)/m);
    nowx=tmp.p[nowx];
    force_move(nowx,nowy,(tm-tm1)%m);
    printf("%d %d\n",nowx,nowy);
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
#endif
    char op[10];
    int x,y,z;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=m;++j)
            scanf("%d",&a[i][j]);
    prework();
    nowx=1; nowy=1;
    scanf("%d",&q);
    for (int i=1;i<=q;++i){
        scanf("%s",op);
        if (op[0]=='m'){
            scanf("%d",&x);
            solve(x);
        }
        else{
            scanf("%d%d%d",&x,&y,&z);
            a[x][y]=z;
            modify(Y(y-1));
        }
    }
}
相關文章
相關標籤/搜索