NOIP2017d2t3 列隊 動態開點線段樹

2021-08-11 06:48:37 字數 1332 閱讀 4076

有乙個n*m的矩陣,一開始位置(x,y)上的元素為(x-1)*m+y。接下來有q個操作:每次操作為(x,y),表示先輸出位置(x,y)上的值,設t為(x,y)上的值,然後把第x行[y+1…m]上的每個數往前移一位,把最後一列[x+1…n]上的每個數往前移一位,最後把t放到位置(n,m)。

n,m,q<=300000

考場上大概想到了做法,但由於乙個地方把n和m打反而少了35分,同時有兩個點被ccf的老爺機卡常。

大概就是說注意到每次操作只會修改某一行和最後一列,我們就對每一行和最後一列分別開一棵線段樹。每次操作的時候就對第x行和最後一列的線段樹各種操作一下。由於每一行和最後一列最多會被插入q個數,所以每棵線段樹的大小要開大q。

這樣顯然會炸空間。但注意到一開始每行線段樹的前m個位置是滿的且元素是公差為1的等差數列,我們便可以先不開這部分的節點,等要用到的時候再把那些節點加上去。這樣就可以保證空間了。

超級好打!

時間複雜度o(nlogn),空間複雜度o(nlogn)。

據說正解是樹狀陣列但並不是太會。。。

#include

#include

#include

#include

#include

using

namespace

std;

typedef

long

long ll;

const

int n=300005;

int n,m,q,sz,num[n],rt[n],tag,z;

struct treet[n*50];

int read()

while (ch>='0'&&ch<='9')

return x*f;

}ll kth(int &d,int l,int r,int k)

else

return t[d].id;

}int mid=(l+r)/2,ls=(!t[d].l?max(0,min(mid,z)-l+1):t[t[d].l].s);

if (ls>=k) return kth(t[d].l,l,mid,k);

else

return kth(t[d].r,mid+1,r,k-ls);

}void ins(int &d,int l,int r,int x,ll y)

int mid=(l+r)/2;

if (x<=mid) ins(t[d].l,l,mid,x,y);

else ins(t[d].r,mid+1,r,x,y);

}int main()

else

}return

0;}

NOIp2017D2T3 列隊(線段樹)

sylvia是乙個熱愛學習的女 孩子。前段時間,sylvia參加了學校的軍訓。眾所周知,軍訓的時候需要站方陣。sylvia 所在的方陣中有 n mn times mn m 名學生,方陣的行數為 nnn 列數為 mmm 為了便於管理,教官在訓練開始時,按照從前到後,從左到右的順序給方陣中 的學生從 1...

NOIP2017提高組正式賽 D2T3列隊

sylvia 是乙個熱愛學習的女孩子。前段時間,sylvia 參加了學校的軍訓。眾所周知,軍訓的時候需要站方陣。sylvia所在的方陣中有n m名學生,方陣的行數為 n,列數為 m。為了便於管理,教官在訓練開始時,按照從前到後,從左到右的順序給方陣中從 1 到 n m 編上了號碼 參見後面的樣例 即...

NOIP2017 列隊(樹狀陣列)

定義第i行為所有的點 i,j 0 可以發現,每一行是相對獨立的,每一次操作只會影響到當前行和最後一列 考慮每一行和最後一列各開乙個樹狀陣列,但這樣顯然會爆空間 實際上,對於沒有離隊過的點是沒必要儲存的,可以直接算出編號,因此只要用vector儲存每一行和最後一列後加入的點即可 還需要預處理乙個陣列d...