題解 P3960 列隊

2021-09-27 13:22:25 字數 1100 閱讀 1361

考慮到每個點都是先橫向移動,然後再縱向移動,所以我們可以考慮每行維護乙個splay,最後一列再維護乙個splay。

但是考慮到n和m的規模都是\(3*10^5\)級別的,普通的splay肯定會爆空間,所以我們使用動態開點的splay,對於每個節點記錄乙個l和乙個r,如果需要splay的元素在這個區間當中,就把當前節點拆成3個,將左側部分和右側部分分別插入到左子樹的最右邊和右子樹的最左邊。

然後接下來就是一些細節問題了:

#includeusing namespace std;

typedef long long ll;

struct node

inline int cmp(int k)

};node *null=new node();

inline node* nn(ll l,ll r)

inline void rotate(node* &o,int d)

void add(node* &o,node *v,int d)

add(o->ch[d],v,d);

o->pu();

}inline void cut(node* &o,int k)

void splay(node* &o,int k)

rotate(o,d^1);

}}inline node* merge(node *left,node *right)

inline void split(node *o,int k,node* &left,node* &right)

inline void dfsx(node* o)

#define print(x) do while(0)

//以上為splay模板

const int maxn=3e5+5;

ll n,m,q;

node *r[maxn],*lst;

int main()

lst=nn(-1,-1);

for(int i=1;i<=n;i++) lst=merge(lst,nn(i*m,i*m));

for(int i=1;i<=q;i++)

else

}return 0;

}

題解 P3960 列隊

考慮到每個點都是先橫向移動,然後再縱向移動,所以我們可以考慮每行維護乙個splay,最後一列再維護乙個splay。但是考慮到n和m的規模都是 3 10 5 級別的,普通的splay肯定會爆空間,所以我們使用動態開點的splay,對於每個節點記錄乙個l和乙個r,如果需要splay的元素在這個區間當中,...

洛谷P3960 列隊(Splay)

傳送門 感覺自己好久不打資料結構已經完全不會了orz 據說正解樹狀陣列?然而並不會 首先考慮一下每一次操作,就是把乙個人從這一行中取出並放到行的最後,再從最後一列取出放到列的最後 那麼這兩種操作其實可以看做同乙個型別,都是把某乙個數取出並放到最後 那麼這個可以用splay來搞,用splay維護區間,...

洛谷P3960 列隊 splay

觀察到向左看齊和向前看齊真正影響的是當前行第y列和當前行的最後乙個人,於是每行除最後乙個建乙個splay,最後一列單獨建乙個splay。對於每次操作,刪除第x個splay樹的第y個,將最後一列的第x個 即第x行最後一列 加入第x個splay樹的末尾,再將刪除的那個節點加入最後一列的splay樹的末尾...