洛谷题目链接:[NOI2005]维护数列
题目描述
请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格)
输入输出格式
输入格式:
输入文件的第 1 行包含两个数 N 和 M,N 表示初始时数列中数的个数,M 表示要进行的操作数目。 第 2 行包含 N 个数字,描述初始时的数列。 以下 M 行,每行一条命令,格式参见问题描述中的表格
输出格式:
对于输入数据中的 GET-SUM 和 MAX-SUM 操作,向输出文件依次打印结 果,每个答案(数字)占一行。
输入输出样例
输入样例#1:
9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM
输出样例#1:
-1
10
1
10
说明
你可以认为在任何时刻,数列中至少有 1 个数。
输入数据一定是正确的,即指定位置的数在数列中一定存在。
50%的数据中,任何时刻数列中最多含有 30 000 个数;
100%的数据中,任何时刻数列中最多含有 500 000 个数。
100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。
100%的数据中,M ≤20 000,插入的数字总数不超过 4 000 000 。
一句话题意: 没啥题意不题意的了...按照题目要求模拟吧...
题解: 这里就重点讲一下要注意的细节吧.
- 因为这个蛇皮的空间限制,我们可以把那些删除的节点的编号记录下来,然后存入队列里反复使用.
- 这题的建树方法很显然是要按照中序遍历结果来建树的.所以在插入之前可以先将要插入的数列先处理成一颗树,然后再将处理出的这颗树接到总数列中.
- 在处理插入的树之前可以先将插入的数列处理成一个比较平衡的树型,也就是取这个插入序列的中间作为处理的这颗子树的根.
- 打修改标记的时候如果要下移修改标记,那么这个反转标记就不需要了.
- 在翻转操作中,前后缀的最长上升子序列都反过来了
- 如果不会求最大子段和可以看看这里,当然splay求解最大子段和也是一样的道理.
- 每次修改之后要pushup.
注意一下这些细节基本上就没问题了.
#include<bits/stdc++.h>
#define debug out(root), printf("
")
using namespace std;
const int N=500000+5;
const int inf=0x3f3f3f3f;
int n, m, root, cnt = 0, a[N], id[N];
char opt[10];
struct splay{
int ch[2], fa, size, mx, lx, rx, sum, upd, rev, val;
}t[N];
queue <int> q;
int gi(){
int ans = 0, f = 1; char i = getchar();
while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();}
while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();}
return ans * f;
}
void out(int x){
if(t[x].ch[0]) out(t[x].ch[0]);
if(t[x].val != -inf) printf("%d ",t[x].val);
if(t[x].ch[1]) out(t[x].ch[1]);
}
bool get(int x){return x == t[t[x].fa].ch[1];}
void up(int x){
int l = t[x].ch[0], r = t[x].ch[1];
t[x].size = t[l].size+t[r].size+1;
t[x].sum = t[l].sum+t[r].sum+t[x].val;
t[x].lx = max(t[l].lx, t[l].sum+t[x].val+t[r].lx);
t[x].rx = max(t[r].rx, t[r].sum+t[x].val+t[l].rx);
t[x].mx = max(max(t[l].mx, t[r].mx), t[l].rx+t[x].val+t[r].lx);
}
void pushdown(int x){
int l = t[x].ch[0], r = t[x].ch[1];
if(t[x].upd){
int v = t[x].val; t[x].upd = t[x].rev = 0;
if(l) t[l].val = v, t[l].upd = 1, t[l].sum = t[l].size*v;
if(r) t[r].val = v, t[r].upd = 1, t[r].sum = t[r].size*v;
if(v >= 0){
if(l) t[l].lx = t[l].rx = t[l].mx = t[l].sum;
if(r) t[r].lx = t[r].rx = t[r].mx = t[r].sum;
} else {
if(l) t[l].lx = t[l].rx = 0, t[l].mx = v;
if(r) t[r].lx = t[r].rx = 0, t[r].mx = v;
}
}
if(t[x].rev){
t[l].rev ^= 1, t[r].rev ^= 1; t[x].rev = 0;
swap(t[l].lx, t[l].rx), swap(t[r].lx, t[r].rx);
swap(t[l].ch[1], t[l].ch[0]); swap(t[r].ch[1], t[r].ch[0]);
}
}
void rotate(int x){
int fa = t[x].fa, gfa = t[fa].fa, d1 = get(x), d2 = get(fa);
t[t[x].ch[d1^1]].fa = fa, t[fa].ch[d1] = t[x].ch[d1^1];
t[fa].fa = x, t[x].ch[d1^1] = fa;
t[x].fa = gfa, t[gfa].ch[d2] = x;
up(fa), up(x);
}
void splay(int x, int goal){
while(t[x].fa != goal){
int fa = t[x].fa, gfa = t[fa].fa, d1 = get(x), d2 = get(fa);
if(goal != gfa){
if(d1 == d2) rotate(fa);
else rotate(x);
}
rotate(x);
}
if(goal == 0) root = x;
}
int kth(int node, int k){
pushdown(node);
int l = t[node].ch[0], r = t[node].ch[1];
if(k <= t[l].size) return kth(l, k);
else if(k == t[l].size+1) return node;
else return kth(r, k-t[l].size-1);
}
void build(int l, int r, int f){
int mid = (l+r>>1), node = id[mid], fa = id[f];
//printf("a[%d]=%d
", mid, a[mid]);
if(l == r){
t[node].mx = t[node].sum = a[l];
t[node].lx = t[node].rx = max(a[l], 0);
t[node].size = 1;
t[node].rev = t[node].upd= 0;
}
if(l < mid) build(l, mid-1, mid);
if(mid < r) build(mid+1, r, mid);
t[node].val = a[mid], t[node].fa = fa;
up(node); t[fa].ch[f<=mid] = node;
}
void insert(int k, int tot){
for(int i=1;i<=tot;i++) a[i] = gi();
for(int i=1;i<=tot;i++)
if(!q.empty()) id[i] = q.front(), q.pop();
else id[i] = ++cnt;
build(1, tot, 0);
int rt = id[1+tot>>1], pre = kth(root, k+1), nex = kth(root, k+2);
splay(pre, 0); splay(nex, pre);
t[nex].ch[0] = rt; t[rt].fa = nex;
up(nex), up(pre);
}
void reuse(int node){
if(t[node].ch[0]) reuse(t[node].ch[0]);
if(t[node].ch[1]) reuse(t[node].ch[1]);
q.push(node);
t[node].ch[0] = t[node].ch[1] = 0;
t[node].fa = t[node].rev = t[node].upd = 0;
}
int split(int k, int tot){
int pre = kth(root, k), nex = kth(root, k+tot+1);
splay(pre, 0); splay(nex, pre);
//printf("pre=%d nex=%d
",pre,nex);
return t[nex].ch[0];
}
void reverse(int k, int tot){
int rt = split(k, tot), fa = t[rt].fa;
if(t[rt].upd == 0){
t[rt].rev ^= 1;
swap(t[rt].ch[0], t[rt].ch[1]);
swap(t[rt].lx, t[rt].rx);
up(fa), up(t[fa].fa);
}
}
void delet(int k, int tot){
int rt = split(k, tot), fa = t[rt].fa;
reuse(rt); t[fa].ch[0] = 0;
up(fa), up(t[fa].fa);
}
void update(int k, int tot, int c){
int rt = split(k, tot), fa = t[rt].fa;
t[rt].val = c, t[rt].upd = 1, t[rt].sum = c*t[rt].size;
if(c >= 0) t[rt].lx = t[rt].rx = t[rt].mx = t[rt].sum;
else t[rt].lx = t[rt].rx = 0, t[rt].mx = c;
up(fa), up(t[fa].fa);
}
int get_sum(int k, int tot){int rt = split(k, tot); return t[rt].sum;}
int max_sum(){return t[root].mx;}
int main(){
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
int x, y, z; n = gi(); m = gi();
a[1] = a[n+2] = t[0].mx = -inf;
for(int i=2;i<=n+1;i++) a[i] = gi();
for(int i=1;i<=n+2;i++) id[i] = i;
build(1, n+2, 0); root = (n+3>>1), cnt = n+2;
for(int i=1;i<=m;i++){
scanf("%s",opt);
if(opt[2] == 'S') x = gi(), y = gi(), insert(x, y);
if(opt[2] == 'L') x = gi(), y = gi(), delet(x, y);
if(opt[2] == 'K') x = gi(), y = gi(), z = gi(), update(x, y, z);
if(opt[2] == 'V') x = gi(), y = gi(), reverse(x, y);
if(opt[2] == 'T') x = gi(), y = gi(), printf("%d
",get_sum(x, y));
if(opt[2] == 'X') printf("%d
",max_sum());
}
return 0;
}
(我Brave_Cattle就是WA死,TLE一年调不出来,也不会要你BZOJ一个数据!....这数据真好用)