有乙個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...