【bzoj1251】序列终结者 Splay
题目描述
网上有许多题,就是给定一个序列,要你支持几种操作:A、B、C、D。一看另一道题,又是一个序列 要支持几种操作:D、C、B、A。尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术含量……这样 我也出一道题,我出这一道的目的是为了让大家以后做这种题目有一个“库”可以依靠,没有什么其他的意思。这道题目 就叫序列终结者吧。 【问题描述】 给定一个长度为N的序列,每个序列的元素是一个整数(废话)。要支持以下三种操作: 1. 将[L,R]这个区间内的所有数加上V。 2. 将[L,R]这个区间翻转,比如1 2 3 4变成4 3 2 1。 3. 求[L,R]这个区间中的最大值。 最开始所有元素都是0。
输入
第一行两个整数N,M。M为操作个数。 以下M行,每行最多四个整数,依次为K,L,R,V。K表示是第几种操作,如果不是第1种操作则K后面只有两个数。
输出
对于每个第3种操作,给出正确的回答。
样例输入
4 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4
样例输出
2
题解
Splay模板题。
然而数组开到50001无故TLE调了1个小时QAQ
由于有哨兵节点,所以开数组时要比平常多2,也就是至少要开到50003!
下次再也不擦边开数组了。。。
#include <cstdio> #include <algorithm> using namespace std; int num[50005] , c[2][50005] , fa[50005] , add[50005] , rev[50005] , maxn[50005] , si[50005] , root; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();} return x * f; } void pushup(int k) { int l = c[0][k] , r = c[1][k]; maxn[k] = max(num[k] , max(maxn[l] , maxn[r])); si[k] = si[l] + si[r] + 1; } void pushdown(int k) { int l = c[0][k] , r = c[1][k]; if(add[k]) { if(l) num[l] += add[k] , maxn[l] += add[k] , add[l] += add[k]; if(r) num[r] += add[k] , maxn[r] += add[k] , add[r] += add[k]; add[k] = 0; } if(rev[k]) { if(l) swap(c[0][l] , c[1][l]) , rev[l] ^= 1; if(r) swap(c[0][r] , c[1][r]) , rev[r] ^= 1; rev[k] = 0; } } void build(int l , int r , int f) { if(l > r) return; int mid = (l + r) >> 1; build(l , mid - 1 , mid); build(mid + 1 , r , mid); fa[mid] = f; pushup(mid); c[mid > f][f] = mid; } void rotate(int &k , int x) { int y = fa[x] , z = fa[y] , l , r; l = (c[0][y] != x); r = l ^ 1; if(y == k) k = x; else if(c[0][z] == y) c[0][z] = x; else c[1][z] = x; fa[x] = z; fa[y] = x; fa[c[r][x]] = y; c[l][y] = c[r][x]; c[r][x] = y; pushup(y); pushup(x); } void splay(int &k , int x) { while(x != k) { int y = fa[x] , z = fa[y]; if(y != k) { if(c[0][y] == x ^ c[0][z] == y) rotate(k , x); else rotate(k , y); } rotate(k , x); } } int find(int k , int r) { pushdown(k); if(r <= si[c[0][k]]) return find(c[0][k] , r); else if(r > si[c[0][k]] + 1) return find(c[1][k] , r - si[c[0][k]] - 1); else return k; } void update(int l , int r , int v) { int lp = find(root , l) , rp = find(root , r + 2) , z; splay(root , lp); splay(c[1][root] , rp); z = c[0][rp]; num[z] += v; maxn[z] += v; add[z] += v; } void rever(int l , int r) { int lp = find(root , l) , rp = find(root , r + 2) , z; splay(root , lp); splay(c[1][root] , rp); z = c[0][rp]; swap(c[0][z] , c[1][z]); rev[z] ^= 1; } int query(int l , int r) { int lp = find(root , l) , rp = find(root , r + 2) , z; splay(root , lp); splay(c[1][root] , rp); z = c[0][rp]; return maxn[z]; } int main() { int n , m , k , l , r , v; maxn[0] = 0x80000000; n = read() , m = read(); build(1 , n + 2 , 0); root = (n + 3) >> 1; while(m -- ) { k = read() , l = read() , r = read(); switch(k) { case 1: v = read(); update(l , r , v); break; case 2: rever(l , r); break; default: printf("%d\n" , query(l , r)); } } return 0; }