資料結構題還是挺好玩的
注意到每次只變動三個點:(x,y),(x,m),(n,m),其他地方都是整塊移動。
可以開n+1個線段樹,前n個存每行前m-1個人,最後乙個存第m列的人。
(x,y)位置的人出列時,抽出該位置的標號,加到第n+1個線段樹的最後面去,抽出第n+1個線段樹的第x個元素(即(x,m),加到第x個線段樹的最後面去。
↑實現這一操作,可以記線段樹的size,每次二分查詢樹上第k個元素即可確定位置。
↑當然樹不可能全建出來,需要動態開點。尚未申請的結點,size直接用$ r-l+1 $計算。
寫到一半想到不需要專門抽出來,只需要記錄該行到該位置為止抽出過a個數,找(x,y)時實際找(x,y+a)即可。可以開個vector什麼的存新加到隊伍最右邊的人。
這樣的話更加方便&優美,而且可以用樹狀陣列寫,**量也減小了。
但是看著自己寫了一大半的**不捨得丟,還是強行按原計畫敲完了。
————
老年退役選手連noip題都做不來了。做這題成功遇到了陣列開小,變數寫混,初始化錯誤,輸出錯誤等等問題,調了好久。
不開心qaq
————
1 #include2 #include3#define ll long long
4using
namespace
std;
5const
int mxn=800010;6
struct
nodet[mxn<<3
];10
int cnt=0,mod=0;11
introot[mxn];
12int
n,n,m,q;
13 inline int getsz(int l,int r,int
rt)17
void pushup(int l,int r,int
rt)25
intanspos;
26int query(int k,int l,int r,int &rt)
31if(l==r)
36 anspos=l;
37return
rt;38}39
int mid=(l+r)>>1,tmp=getsz(l,mid,t[rt].lc);
40if(k<=tmp)
41return
query(k,l,mid,t[rt].lc);
42else
return query(k-tmp,mid+1
,r,t[rt].rc);43}
44void update(ll v,int p,int l,int r,int &rt)
49if(l==r)
54else t[rt].sz=1;55
return;56
}57int mid=(l+r)>>1;58
if(p<=mid)update(v,p,l,mid,t[rt].lc);
59else update(v,p,mid+1
,r,t[rt].rc);
60pushup(l,r,rt);
61return;62
}63void info(int l,int r,int
rt)72
intmain()
90else
113//
info(1,n,root[n+1]);
114}
115return0;
116 }
洛谷P3953 NOIp2017 逛公園
考慮到邊權可能為 0 轉移的順序會影響最後的結果,因此我們用記憶化搜尋代替直接dp 0 環 如何判斷乙個點 u是否在滿足條件的路徑上?顯然我們可以知道這個點滿足di s1 u di sn u di s1 n k 我們把所有長度為 0 的邊建成乙個新圖,然後用ta rjan 找出所有點數大於 1 的強...
洛谷P3960 列隊(Splay)
傳送門 感覺自己好久不打資料結構已經完全不會了orz 據說正解樹狀陣列?然而並不會 首先考慮一下每一次操作,就是把乙個人從這一行中取出並放到行的最後,再從最後一列取出放到列的最後 那麼這兩種操作其實可以看做同乙個型別,都是把某乙個數取出並放到最後 那麼這個可以用splay來搞,用splay維護區間,...
洛谷P3960 列隊 splay
觀察到向左看齊和向前看齊真正影響的是當前行第y列和當前行的最後乙個人,於是每行除最後乙個建乙個splay,最後一列單獨建乙個splay。對於每次操作,刪除第x個splay樹的第y個,將最後一列的第x個 即第x行最後一列 加入第x個splay樹的末尾,再將刪除的那個節點加入最後一列的splay樹的末尾...