link

题目大意:维护一个序列

支持:

1.单点插入

2.单点删除

3.区间翻转

4.区间旋转

5.区间加

6.区间赋值

7.询问区间和

8.询问区间极差

9.询问区间与给定某个数差值绝对值的最小值

10.询问区间第k小

11.询问区间某个数排名

艹 11个操作 太毒瘤了 写了一下午+晚上一节课(包含中途透彻时间

这么多操作各种平衡树都上不了了,就块状链表

操作1:找到位置,把一个块拆分,转化为在快末尾插入

操作2:拆分块,转化为在块末尾删除

操作3:把翻转的区间拎出来,每个区间打个翻转标记,然后指针瞎指下

操作4:把旋转的区间拎出来,每个区间打个旋转标记

操作5:把区间拎出来打加法标记

操作6:把区间拎出来打赋值标记

操作7:把区间拎出来维护区间sum直接求和

操作8:每个块维护s数组代表块内元素排序好的结果,把区间拎出来后直接询问,每个块返回s[0]和s[size-1]

操作9:每个块s数组里lower_bound和upper_bound

操作10:二分,转化为操作11

操作11:每个块s数组里lower_bound

细节:

0.每次操作后遍历整个链表,检查两个相邻块大小太小就要合并

每个块维护a[],s[],sz,sum,三个标记,链表指针

区间赋值标记优先级比另外两个高,另外两个可以共存

需要对某个块进行大修改(分裂/合并)等之前要先清除标记,区间查询内不能清除标记

块尾insert和delete维护s数组要用插入排序及其逆操作

。。。忘了还有啥要注意的了

#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std; struct fuck
{
int a[1000], s[1000]; //原序列/有序序列
int sz, chenge_flag, add_flag;
//chenge_flag存在时忽视add_flag和rev_flag
//不存在时另外两个标记互相不影响
long long sum; //和
bool rev_flag; //翻转标记
fuck *nex; //下个指针 fuck()
{
sz = 0;
sum = 0;
nex = 0;
chenge_flag = -1;
add_flag = 0;
rev_flag = false;
}
void access()
{
if (chenge_flag != -1)
{
for (int i = 0; i < sz; i++) a[i] = s[i] = chenge_flag;
sum = sz * (long long)chenge_flag;
chenge_flag = -1;
}
else
{
if (add_flag != 0)
{
for (int i = 0; i < sz; i++) a[i] += add_flag, s[i] += add_flag;
sum += sz * (long long)add_flag;
add_flag = 0;
}
if (rev_flag != 0) {reverse(a, a + sz); rev_flag ^= 1; }
}
}
void gc(int x)
{
add_flag = rev_flag = 0;
chenge_flag = x;
}
void ga(int x)
{
if (chenge_flag == -1) add_flag += x;
else chenge_flag += x;
}
void gr()
{
if (chenge_flag == -1) rev_flag ^= 1;
}
void push_back(int x)
{
access();
//维护s
if (sz == 0 || x >= s[sz - 1]) s[sz] = x;
else for (int i = sz - 1; i >= 0; i--)
{
s[i + 1] = s[i];
if (i == 0 || s[i - 1] <= x) { s[i] = x; break; }
}
//维护sum和a
sum += (a[sz++] = x);
}
void delete_back()
{
access();
sum -= a[sz - 1];
for (int i = 0 ;i < sz; i++)
{
if (s[i] == a[sz - 1])
{
for (int j = i + 1; j < sz; j++)
s[j - 1] = s[j];
}
}
sz--;
}
int qmax()
{
if (sz == 0) return 0;
else if (chenge_flag != -1) return chenge_flag;
else return s[sz - 1] + add_flag;
}
int qmin()
{
if (sz == 0) return 0x7fffffff;
else if (chenge_flag != -1) return chenge_flag;
else return s[0] + add_flag;
}
long long qsum()
{
if (chenge_flag != -1) return chenge_flag * (long long)sz;
else return sum + add_flag * (long long)sz;
}
int query(int val)
{
if (chenge_flag != -1) return chenge_flag < val ? sz : 0;
val -= add_flag;
return lower_bound(s, s + sz, val) - s;
}
int mindis(int val)
{
if (sz == 0) return 0x7fffffff;
if (chenge_flag != -1) return abs(chenge_flag - val);
val -= add_flag;
int pos0 = lower_bound(s, s + sz, val) - s;
if (pos0 < sz && s[pos0] == val) return 0; else pos0--;
int pos1 = upper_bound(s, s + sz, val) - s;
if (pos0 >= 0 && pos0 < sz) pos0 = val - s[pos0];
else pos0 = 0x7fffffff;
if (pos1 >= 0 && pos1 < sz) pos1 = s[pos1] - val;
else pos1 = 0x7fffffff;
// printf("id = %p, [%d, %d
return min(pos0, pos1);
}
void print(bool p = 0)const
{
printf("------------\n某一块%p\n大小%d,和为%lld\nnex=%p\n", this, sz, sum, nex);
printf("c=%d, a=%d, r=%d\n", chenge_flag, add_flag, rev_flag);
for (int i = 0; i < sz; i++) { printf("%d ", a[i]);} printf("\n");
for (int i = 0; i < sz; i++) { printf("%d ", s[i]);} printf("\n");
if (p && nex != 0) nex->print(p); //输出下一页
}
}; int n, m, init[100010];
int blocksz, cur;
fuck *start; fuck *newnode() { return new fuck; }
void delnode(fuck *x) { delete x; } fuck *split(fuck *x, int pos) //x保留pos个元素,在x后面新建一个节点
{
x->access();
if (pos > x->sz) { printf("fuck!\n"); return 0; }
fuck *res = newnode();
//-----维护res
for (int i = pos; i < x->sz; i++)
res->sum += (res->a[i - pos] = res->s[i - pos] = x->a[i]);
res->sz = x->sz - pos;
sort(res->s, res->s + res->sz);
res->nex = x->nex;
//-----维护x
x->sz = pos; x->sum = 0;
for (int i = 0; i < pos; i++) x->sum += (x->s[i] = x->a[i]);
sort(x->s, x->s + pos);
x->nex = res;
return res;
} void merge(fuck *x)
{
x->access();
x->nex->access();
fuck *p = x->nex;
for (int i = 0; i < p->sz; i++)
x->sum += (x->a[x->sz + i] = p->a[i]);
x->sz += p->sz;
x->nex = p->nex;
for (int i = 0; i < x->sz; i++) x->s[i] = x->a[i];
sort(x->s, x->s + x->sz);
delnode(p);
} void maintain()
{
for (fuck *p = start; p != 0; p = p->nex)
{
while (p->nex != 0 && p->sz + p->nex->sz <= blocksz)
merge(p);
}
} void get(int l, int r, fuck* &lp, fuck* &rp)
{
lp = start;
while (lp != 0)
{
if (l <= lp->sz) break;
l -= lp->sz;
lp = lp->nex;
}
if (l != 1)
split(lp, l - 1), lp = lp->nex;
rp = start;
while (rp != 0)
{
if (r <= rp->sz) break;
r -= rp->sz;
rp = rp->nex;
}
if (r != rp->sz)
split(rp, r);
} void del(fuck *z)
{
if (z->nex) del(z->nex);
delete z;
} void chkmax(int &a, int b) { if (a < b) a = b; }
void chkmin(int &a, int b) { if (a > b) a = b; } int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &init[i]);
scanf("%d", &m);
blocksz = sqrt(n + m / 5) * 3 / 4;
fuck *now = start = newnode();
for (int i = 1; i <= n; i++)
{
now->push_back(init[i]);
if (i % blocksz == 0 && i != n)
{
fuck *p = newnode();
now->nex = p;
now = p;
}
}
for (int opd, x, y, k, val, i = 1; i <= m; i++)
{
scanf("%d", &opd);
switch (opd)
{
case 1:
{
scanf("%d%d", &x, &val);
fuck *p = start;
while (p != 0)
{
if (x <= p->sz) break;
x -= p->sz;
p = p->nex;
}
//从0开始计数,放在p的第x个位置,也就是说p前面有x个数
split(p, x);
p->push_back(val);
maintain();
break;
}
case 2:
{
scanf("%d", &x);
fuck *p = start;
while (p != 0)
{
if (x <= p->sz) break;
x -= p->sz;
p = p->nex;
}
//删除第x个数,所以前面需要x个数
split(p, x);
p->delete_back();
maintain();
break;
}
case 3:
{
scanf("%d%d", &x, &y);
fuck *l, *r;
get(x, y, l, r), r = r->nex;
vector<fuck*> li;
split(l, 0);
for (fuck *p = l->nex; p != r; p = p->nex)
li.push_back(p), p->gr();
l->nex = li[li.size() - 1];
for (int i = li.size() - 1; i > 0; i--)
li[i]->nex = li[i - 1];
li[0]->nex = r;
maintain();
break;
}
case 4:
{
scanf("%d%d%d", &x, &y, &k);
fuck *l1, *r1, *l2, *r2;
get(x, y - k, l1, r1);
get(y - k + 1, y, l2, r2);
if (start == l1) start = l2;
else
{
fuck *p = start;
while (p->nex != l1) p = p->nex;
p->nex = l2;
}
r1->nex = r2->nex;
r2->nex = l1;
maintain();
break;
}
case 5:
{
scanf("%d%d%d", &x, &y, &val);
fuck *l, *r;
get(x, y, l, r), r = r->nex;
for (fuck *p = l; p != r; p = p->nex)
p->ga(val);
maintain();
break;
}
case 6:
{
scanf("%d%d%d", &x, &y, &val);
fuck *l, *r;
get(x, y, l, r), r = r->nex;
for (fuck *p = l; p != r; p = p->nex)
p->gc(val);
maintain();
break;
}
case 7:
{
scanf("%d%d", &x, &y);
fuck *l, *r;
get(x, y, l, r), r = r->nex;
long long ans = 0;
for (fuck *p = l; p != r; p = p->nex)
ans += p->qsum();
printf("%lld\n", ans);
maintain();
break;
}
case 8:
{
scanf("%d%d", &x, &y);
fuck *l, *r;
get(x, y, l, r), r = r->nex;
int maxn = 0, minn = 0x7fffffff;
for (fuck *p = l; p != r; p = p->nex)
chkmax(maxn, p->qmax()), chkmin(minn, p->qmin());
printf("%d\n", maxn - minn);
maintain();
break;
}
case 9:
{
scanf("%d%d%d", &x, &y, &val);
fuck *l, *r;
get(x, y, l, r), r = r->nex;
int res = 0x7fffffff;
for (fuck *p = l; p != r; p = p->nex)
chkmin(res, p->mindis(val));
printf("%d\n", res);
maintain();
break;
}
case 10:
{
scanf("%d%d%d", &x, &y, &k);
fuck *l, *r;
get(x, y, l, r), r = r->nex;
long long cl = 1, cr = 0x7fffffff;
while (cl < cr)
{
long long mid = (cl + cr) / 2;
int tot = 0;
for (fuck *p = l; p != r; p = p->nex)
tot += p->query(mid);
if (tot >= k) cr = mid;
else cl = mid + 1;
}
printf("%lld\n", cl - 1);
maintain();
break;
}
case 11:
{
scanf("%d%d%d", &x, &y, &val);
fuck *l, *r;
get(x, y, l, r), r = r->nex;
int ans = 0;
for (fuck *p = l; p != r; p = p->nex)
ans += p->query(val);
printf("%d\n", ans);
maintain();
break;
}
}
}
del(start);
return 0;
}

[BZOJ3337] ORZJRY I --块状链表大毒瘤的更多相关文章

  1. 【BZOJ-3337】ORZJRY I 块状链表

    3337: ORZJRY I Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 190  Solved: 50[Submit][Status][Discu ...

  2. ZOJ 2112 Dynamic Rankings(动态区间第 k 大+块状链表)

    题目大意 给定一个数列,编号从 1 到 n,现在有 m 个操作,操作分两类: 1. 修改数列中某个位置的数的值为 val 2. 询问 [L, R] 这个区间中第 k 大的是多少 n<=50,00 ...

  3. 【BZOJ-1507】Editor 块状链表

    1507: [NOI2003]Editor Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 3397  Solved: 1360[Submit][Stat ...

  4. 【BZOJ 1507】【NOI 2003】&【Tyvj P2388】Editor 块状链表模板题

    2016-06-18 当时关于块状链表的想法是错误的,之前维护的是一个动态的$\sqrt{n}$,所以常数巨大,今天才知道原因TwT,请不要参照这个程序为模板!!! 模板题水啊水~~~ 第一次写块状链 ...

  5. BZOJ 1507 Editor(块状链表)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1507 题意:一个文本编辑器,模拟以下操作: 思路:块状链表的主要操作: (1)find( ...

  6. 【BZOJ1500】【块状链表】维修数列

    Description Input 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述 ...

  7. 【BZOJ3295】【块状链表+树状数组】动态逆序对

    Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计 ...

  8. 【HDU4391】【块状链表】Paint The Wall

    Problem Description As a amateur artist, Xenocide loves painting the wall. The wall can be considere ...

  9. LOJ.6282.数列分块入门6(块状链表/分块)

    题目链接 1.分块(vector)+重构 //直接上vector(本机还是比较慢的...) 某块size较大时O(n)重构 //注意细节 #include <cmath> #include ...

随机推荐

  1. Spring学习十一

    一:  创建bean的方法: 1: 如果不采用构造注入:默认调用bean的无参构造函数,因此该类必须要提供无参构造函数,用无参构造函数用反射创建bean. :               如果采用构造 ...

  2. Android 4学习(4):概述 - Using Resources

    参考:<Professional Android 4 Application Development> Andorid中的资源包括用户自定义资源和系统自带资源,这两种资源既可以在代码中使用 ...

  3. 10-12C#基础--运算符

    10-12C#基础--运算符 课前作业:班级内人数的姓名和年龄,分别写出之后并汇总. 一.运算符的分类 1.数学运算符(7个) 1)+(加号) 例: 2)-(减号) 例: 3)*(乘号) 例: 4)/ ...

  4. 使用matplotlib的示例:调整字体-设置刻度、坐标、colormap和colorbar等

    使用matplotlib的示例:调整字体-设置刻度.坐标.colormap和colorbar等 2013-08-09 19:04 27805人阅读 评论(1) 收藏 举报  分类: Python(71 ...

  5. Linux-CentOS 学习的坎坷路 (一) 网络配置篇

    自己学习的地址:http://www.imooc.com/view/175 学到2.8章节,配置IP这一块,妈蛋,他直接跳过了,都不知道怎么配置,无奈,只能Search 先是找到配置IP的方法: ht ...

  6. IO流框架关系总结(关系图)

    字节流和字符流关系图  打印流和序列化流关系图

  7. 【转】mysql.sock文件的作用

    Mysql有两种连接方式: (1),TCP/IP (2),socket 对mysql.sock来说,其作用是程序与mysqlserver处于同一台机器,发起本地连接时可用. (如果程序跟mysql在同 ...

  8. Windows系统 安装 CMake

    Windows系统 安装 CMake 我们的电脑系统:Windows 10 64位 安装的CMake 版本:cmake-3.6.1-win64-x64(目前最新) 下载 在CMake官网下载:cmak ...

  9. 算法Sedgewick第四版-第1章基础-2.1Elementary Sortss-008排序算法的复杂度(比较次数的上下限)

    一. 1. 2.

  10. 关于LIst Set Map 异常的知识点---我的笔记

    今天新的内容1.List接口2.Set接口3.Map集合4.异常==================================================================== ...