Description
网上有许多题,就是给定一个序列,要你支持几种操作: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。 Input
第一行两个整数N,M。M为操作个数。 以下M行,每行最多四个整数,依次为K,L,R,V。K表示是第几种操作,如果不是第1种操作则K后面只有两个数。 Output
对于每个第3种操作,给出正确的回答。 Sample Input 4 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4
Sample Output 2
【数据范围】
N<=50000,M<=100000。
Splay裸题。
//bzoj 1251 splay 复习//支持操作为//1: 区间+//2: 区间翻转//3: 区间求最大#include <bits/stdc++.h>using namespace std;const int maxn = 50010;const int maxm = 100010;namespace SplayTree{ int siz[maxn], fa[maxn], ma[maxn], rev[maxn], lazy[maxn], val[maxn]; //siz代表节点的sz,fa代表父亲节点,ma代表最大值,rev翻转标记 //lazy 区间+, val 值 int ch[maxn][2], tot, root; //tot代表开新节点的时间戳,root代表splay的树根,ch[i][2],i的左右儿子 void newnode(int &rt, int father, int k){ rt = ++tot; siz[rt] = 1, fa[rt] = father; ma[rt] = val[rt] = k; rev[rt] = lazy[rt] = ch[rt][0] = ch[rt][1] = 0; } void pushup(int rt){ //pushup 从底向上更新 siz[rt] = 1, ma[rt] = val[rt]; if(ch[rt][0] != 0) siz[rt] += siz[ch[rt][0]], ma[rt] = max(ma[rt], ma[ch[rt][0]]); if(ch[rt][1] != 0) siz[rt] += siz[ch[rt][1]], ma[rt] = max(ma[rt], ma[ch[rt][1]]); } void pushdown(int rt){ //pushdown 从上向下更新 if(!rt) return; if(lazy[rt]){ //区间+懒惰标记传递 int l = ch[rt][0], r = ch[rt][1]; if(l != 0) ma[l] += lazy[rt], val[l] += lazy[rt], lazy[l] += lazy[rt]; if(r != 0) ma[r] += lazy[rt], val[r] += lazy[rt], lazy[r] += lazy[rt]; lazy[rt] = 0; } if(rev[rt]){ //区间翻转懒惰标记传递 int l = ch[rt][0], r = ch[rt][1]; if(l != 0) rev[l] ^= 1, swap(ch[l][0], ch[l][1]); if(r != 0) rev[r] ^= 1, swap(ch[r][0], ch[r][1]); rev[rt] ^= 1; } } void rotate(int x){ //旋转,把x转到根节点,kind为1代表右旋,kind为0代表左旋 int y = fa[x], kind = ch[y][1] == x; pushdown(y), pushdown(x); ch[y][kind] = ch[x][!kind]; fa[ch[y][kind]] = y; ch[x][!kind] = y; fa[x] = fa[y]; fa[y] = x; ch[fa[x]][ch[fa[x]][1] == y] = x; pushup(y), pushup(x); } void splay(int x, int goal) //伸展操作,把根为r的子树调整为goal { while(fa[x] != goal) { int y = fa[x], z = fa[y]; if(z == goal) rotate(x); else if((ch[y][1] == x) == (ch[z][1] == y)) rotate(y), rotate(x); else rotate(x), rotate(x); } if(goal == 0) root = x; } void build(int &rt, int l, int r, int father){ //建立一颗空的splaytree if(l > r) return; int mid = (l + r) / 2; newnode(rt, father, 0); //递归申请新节点 build(ch[rt][0], l, mid - 1, rt); build(ch[rt][1], mid + 1, r, rt); pushup(rt); } int find(int x, int k){ //查找第k位置在splaytree中的位置 pushdown(x); int lsum = siz[ch[x][0]] + 1; if(lsum == k) return x; else if(lsum < k) return find(ch[x][1], k - lsum); else return find(ch[x][0], k); } void update_val(int l, int r, int v){ //区间更新+ splay(find(root, l), 0); splay(find(root, r + 2), root); lazy[ch[ch[root][1]][0]] += v; ma[ch[ch[root][1]][0]] += v; val[ch[ch[root][1]][0]] += v; } void update_rev(int l, int r){ splay(find(root, l), 0); splay(find(root, r + 2), root); int tmp = ch[ch[root][1]][0]; //现在以tmp为根的splaytree就是l,r区间 rev[tmp] ^= 1; swap(ch[tmp][0], ch[tmp][1]); } int querymax(int l, int r){ //查询区间最大值 splay(find(root, l), 0); splay(find(root, r + 2), root); return ma[ch[ch[root][1]][0]]; }}using namespace SplayTree;int main(){ int n, m; scanf("%d%d", &n, &m); newnode(root, 0, -1); newnode(ch[root][1], root, -1); build(ch[ch[root][1]][0], 1, n, ch[root][1]); for(int i = 1; i <= m; i++){ int cmd, a, b, c; scanf("%d", &cmd); if(cmd == 1){ scanf("%d%d%d", &a, &b, &c); update_val(a, b, c); }else if(cmd == 2){ scanf("%d%d", &a, &b); update_rev(a, b); }else{ scanf("%d%d", &a, &b); PRintf("%d/n", querymax(a, b)); } } return 0;}新闻热点
疑难解答