bzoj3678 wangxz与OJ
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3678
【题解】
好久没写Splay了,看到这题splay很开心码了十分钟写完了交上去,一看怎么T了
仔细一看,插入原来不能暴力插入啊,复杂度会到达$O(nq)$的,只要每次插入100000,再删除,重复就行了。
然后就学习了新姿势
splay每个节点维护$[L,R]$表示这个节点表示的不是一个数,而是数的连续区间$[L,R]$,特别的,当$L=R=-1$的时候,表示这个节点有具体的值(其实好像不用这么麻烦)
那么每次有访问到这个区间里某个具体的数,就暴力把区间split成三块,很明显只会用到中间这块,那么直接提取就行了。
复杂度就很科学了。反正20000询问怎么做都能过(逃
# include <queue> # include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10; const int mod = 1e9+7; # define RG register # define ST static int n, m, a[M], id[M]; struct Splay { int ch[M][2], fa[M], val[M], sz[M], siz, rt; int L[M], R[M]; // -1: no tag queue<int> re; inline int newnode() { if(!re.empty()) { int t = re.front(); re.pop(); return t; } return ++siz; } inline void set() { memset(ch, 0, sizeof ch); memset(fa, 0, sizeof fa); memset(sz, 0, sizeof sz); memset(val, 0, sizeof val); while(!re.empty()) re.pop(); siz = 0; rt = 0; } inline void up(int x) { if(!x) return ; sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + R[x] - L[x] + 1; } inline void rotate(int x, int &rt) { int y = fa[x], z = fa[y], ls = ch[y][1] == x, rs = ls^1; if(rt == y) rt = x; else ch[z][ch[z][1] == y] = x; fa[ch[x][rs]] = y, fa[y] = x, fa[x] = z; ch[y][ls] = ch[x][rs]; ch[x][rs] = y; up(y), up(x); } inline void splay(int x, int &rt) { while(x != rt) { int y = fa[x], z = fa[y]; if(y != rt) { if((ch[y][0] == x) ^ (ch[z][0] == y)) rotate(x, rt); else rotate(y, rt); } rotate(x, rt); } } inline int find(int x, int rk) { if(sz[ch[x][0]] >= rk) return find(ch[x][0], rk); if(sz[ch[x][0]] + (R[x] - L[x] + 1) < rk) return find(ch[x][1], rk - sz[ch[x][0]] - (R[x] - L[x] + 1)); if(L[x] != -1 || R[x] != -1) { rk -= sz[ch[x][0]]; // an seq, split into two seqs if(rk != 1) { int y = newnode(); ch[y][0] = ch[x][0]; fa[ch[y][0]] = y; ch[x][0] = y, fa[y] = x; L[y] = L[x], R[y] = L[x] + rk - 1 - 1; if(L[y] == R[y]) val[y] = L[y], L[y] = R[y] = -1; up(y); } if(rk != R[x] - L[x] + 1) { int y = newnode(); ch[y][1] = ch[x][1]; fa[ch[y][1]] = y; ch[x][1] = y, fa[y] = x; R[y] = R[x], L[y] = L[x] + rk; if(L[y] == R[y]) val[y] = R[y], L[y] = R[y] = -1; up(y); } val[x] = L[x] + rk - 1; L[x] = -1, R[x] = -1; up(x); } return x; } // origin [x, y] inline int split(int u, int v) { int x = find(rt, u), y = find(rt, v+2); splay(x, rt); splay(y, ch[x][1]); return ch[y][0]; } // need update inline void ins(int l, int r, int f) { if(l > r) return; int mid = l+r>>1, x = id[mid], lst = id[f]; if(l != r) ins(l, mid-1, mid), ins(mid+1, r, mid); L[x] = R[x] = -1; val[x] = a[mid]; ch[lst][mid >= f] = x; fa[x] = lst; up(x); } inline void op_1(int p, int a, int b) { int x = find(rt, p+1), y = find(rt, p+2), ps = newnode(); splay(x, rt); splay(y, ch[x][1]); ch[y][0] = ps; fa[ps] = y; L[ps] = a, R[ps] = b; sz[ps] = R[ps] - L[ps] + 1; if(a == b) val[ps] = L[ps], L[ps] = R[ps] = -1; up(y); up(x); } inline void del(int x) { if(!x) return ; del(ch[x][0]); del(ch[x][1]); L[x] = R[x] = -1; ch[x][0] = ch[x][1] = fa[x] = val[x] = 0; sz[x] = 0; re.push(x); } inline void op_2(int u, int v) { int x = split(u, v), y = fa[x]; ch[y][0] = 0; del(x); up(y), up(fa[y]); } inline void op_3(int u) { int x = split(u, u); printf("%d\n", val[x]); } inline void debug(int x) { if(!x) return ; printf("x = %d, ls = %d, rs = %d, L = %d, R = %d, val = %d, sz = %d\n", x, ch[x][0], ch[x][1], L[x], R[x], val[x], sz[x]); debug(ch[x][0]); debug(ch[x][1]); } }T; int main() { // freopen("3678.in", "r", stdin); // freopen("3678.out", "w", stdout); int Q, op, p, b, c; cin >> n >> Q; T.set(); for (int i=2; i<=n+1; ++i) scanf("%d", a+i); for (int i=1; i<=n+2; ++i) id[i] = i; T.ins(1, n+2, 0); T.siz = n+2; T.rt = (n+3 >> 1); while(Q--) { // T.debug(T.rt); scanf("%d", &op); if(op == 0) { scanf("%d%d%d", &p, &b, &c); T.op_1(p, b, c); } else if(op == 1) { scanf("%d%d", &b, &c); T.op_2(b, c); } else { scanf("%d", &p); T.op_3(p); } } // T.debug(T.rt); return 0; } /* 5 3 2 3 3 5 7 0 0 2 3 2 1 2 2 */
顺便贴一份复杂度错的代码
# include <queue> # include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10; const int mod = 1e9+7; # define RG register # define ST static namespace FF { const int n=131072; char ch,B[1<<20],*S=B,*T=B; #define getc() (S==T&&(T=(S=B)+fread(B,1,1<<20,stdin),S==T)?0:*S++) #define isd(c) (c>='0'&&c<='9') int aa,bb;int F(){ while(ch=getc(),!isd(ch)&&ch!='-');ch=='-'?aa=bb=0:(aa=ch-'0',bb=1); while(ch=getc(),isd(ch))aa=aa*10+ch-'0';return bb?aa:-aa; } } #define gi FF::F() #define BUFSIZE 5000000 namespace fob {char b[BUFSIZE]={},*f=b,*g=b+BUFSIZE-2;} #define pob (fwrite(fob::b,sizeof(char),fob::f-fob::b,stdout),fob::f=fob::b,0) #define pc(x) (*(fob::f++)=(x),(fob::f==fob::g)?pob:0) struct foce {~foce() {pob; fflush(stdout);}} _foce; namespace ib {char b[100];} inline void pint(int x) { if(x==0) {pc(48); return;} //if(x<0) {pc('-'); x=-x;} //如果有负数就加上 char *s=ib::b; while(x) *(++s)=x%10, x/=10; while(s!=ib::b) pc((*(s--))+48); } int n, m, a[M], id[M]; struct Splay { int ch[M][2], fa[M], val[M], sz[M], siz, rt; queue<int> re; inline void set() { memset(ch, 0, sizeof ch); memset(fa, 0, sizeof fa); memset(sz, 0, sizeof sz); memset(val, 0, sizeof val); while(!re.empty()) re.pop(); } inline void up(int x) { if(!x) return ; sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1; } inline void rotate(int x, int &rt) { int y = fa[x], z = fa[y], ls = ch[y][1] == x, rs = ls^1; if(rt == y) rt = x; else ch[z][ch[z][1] == y] = x; fa[ch[x][rs]] = y, fa[y] = x, fa[x] = z; ch[y][ls] = ch[x][rs]; ch[x][rs] = y; up(y), up(x); } inline void splay(int x, int &rt) { while(x != rt) { int y = fa[x], z = fa[y]; if(y != rt) { if((ch[y][0] == x) ^ (ch[z][0] == y)) rotate(x, rt); else rotate(y, rt); } rotate(x, rt); } } inline int find(int x, int rk) { if(sz[ch[x][0]] + 1 == rk) return x; if(sz[ch[x][0]] + 1 < rk) return find(ch[x][1], rk - sz[ch[x][0]] - 1); else return find(ch[x][0], rk); } // origin [x, y] inline int split(int u, int v) { int x = find(rt, u), y = find(rt, v+2); splay(x, rt); splay(y, ch[x][1]); return ch[y][0]; } // need update inline void ins(int l, int r, int f) { if(l > r) return; int mid = l+r>>1, x = id[mid], lst = id[f]; if(l == r) sz[x] = 1; else ins(l, mid-1, mid), ins(mid+1, r, mid); val[x] = a[mid]; ch[lst][mid >= f] = x; fa[x] = lst; up(x); } inline void op_1(int p, int m) { for (int i=1; i<=m; ++i) if(!re.empty()) id[i] = re.front(), re.pop(); else id[i] = ++siz; ins(1, m, 0); int ps = id[(m+1) >> 1]; int x = find(rt, p+1), y = find(rt, p+2); splay(x, rt); splay(y, ch[x][1]); ch[y][0] = ps; fa[ps] = y; up(y), up(x); } inline void del(int x) { if(!x) return ; del(ch[x][0]); del(ch[x][1]); ch[x][0] = ch[x][1] = fa[x] = val[x] = 0; sz[x] = 0; re.push(x); } inline void op_2(int u, int v) { int x = split(u, v); del(x); } inline void op_3(int u) { int x = split(u, u); pint(val[x]), pc(10); } }T; int main() { int Q, op, p, b, c; n = gi, Q = gi; T.set(); for (int i=2; i<=n+1; ++i) a[i] = gi; for (int i=1; i<=n+2; ++i) id[i] = i; T.ins(1, n+2, 0); T.siz = n+2; T.rt = (n+3 >> 1); while(Q--) { op = gi; if(op == 0) { p = gi, b = gi, c = gi; m = c-b+1; for (int i=1; i<=m; ++i) a[i] = b+i-1; T.op_1(p, m); } else if(op == 1) { b = gi, c = gi; T.op_2(b, c); } else { p = gi; T.op_3(p); } } return 0; }