[NOI2005] 维护数列(treap)

【问题描述】
请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格)
操作编号
输入文件中的格式
说明

  1. 插入
    INSERT_posi_tot_c1_c2_…_ctot
    在当前数列的第 posi 个数字后插入 tot
    个数字:c1, c2, …, ctot;若在数列首插
    入,则 posi 为 0
  2. 删除
    DELETE_posi_tot
    从当前数列的第 posi 个数字开始连续
    删除 tot 个数字
  3. 修改
    MAKE-SAME_posi_tot_c
    将当前数列的第 posi 个数字开始的连
    续 tot 个数字统一修改为 c
  4. 翻转
    REVERSE_posi_tot
    取出从当前数列的第 posi 个数字开始
    的 tot 个数字,翻转后放入原来的位置
  5. 求和
    GET-SUM_posi_tot
    计算从当前数列开始的第 posi 个数字
    开始的 tot 个数字的和并输出
  6. 求和最大的子列
    MAX-SUM
    求出当前数列中和最大的一段子列,
    并输出最大和
    【输入格式】
    输入文件的第 1 行包含两个数 N 和 M,N 表示初始时数列中数的个数,M表示要进行的操作数目。
    第 2 行包含 N 个数字,描述初始时的数列。
    以下 M 行,每行一条命令,格式参见问题描述中的表格。
    【输出格式】
    对于输入数据中的 GET-SUM 和 MAX-SUM 操作,向输出文件依次打印结果,每个答案(数字)占一行。
    【输入样例】
    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
    10
    1
    10
    【样例说明】
    初始时,我们拥有数列 2 -6 3 5 1 -5 -3 6 3
    执行操作 GET-SUM 5 4,表示求出数列中从第 5 个数开始连续 4 个数字之和,1+(-5)+(-3)+6 = -1:
    2 -6 3 5 1 -5 -3 6 3
    执行操作 MAX-SUM,表示要求求出当前数列中最大的一段和,应为 3+5+1+(-5)+(-3)+6+3 = 10:
    2 -6 3 5 1 -5 -3 6 3
    执行操作 INSERT 8 3 -5 7 2,即在数列中第 8 个数字后插入-5 7 2,
    2 -6 3 5 1 -5 -3 6 -5 7 2 3
    执行操作 DELETE 12 1,表示删除第 12 个数字,即最后一个:
    2 -6 3 5 1 -5 -3 6 -5 7 2
    执行操作 MAKE-SAME 3 3 2,表示从第 3 个数开始的 3 个数字,统一修改为 2:
    2 -6 3 5 1 -5 -3 6 -5 7 2
    改为
    2 -6 2 2 2 -5 -3 6 -5 7 2
    执行操作 REVERSE 3 6,表示取出数列中从第 3 个数开始的连续 6 个数:
    2 -6 2 2 2 -5 -3 6 -5 7 2
    如上所示的灰色部分 2 2 2 -5 -3 6,翻转后得到 6 -3 -5 2 2 2,并放回原来位置:
    2 -6 6 -3 -5 2 2 2 -5 7 2
    最后执行 GET-SUM 5 4 和 MAX-SUM,不难得到答案 1 和 10。
    2 -6 6 -3 -5 2 2 2 -5 7 2
    【评分方法】
    本题设有部分分,对于每一个测试点:
    如果你的程序能在输出文件正确的位置上打印 GET-SUM 操作的答案,你可以得到该测试点 60%的分数;
    如果你的程序能在输出文件正确的位置上打印 MAX-SUM 操作的答案,你可以得到该测试点 40%的分数;
    以上两条的分数可以叠加,即如果你的程序正确输出所有 GET-SUM 和MAX-SUM 操作的答案,你可以得到该测试点 100%的分数。
    请注意:如果你的程序只能正确处理某一种操作,请确定在输出文件正确的位置上打印结果,即必须为另一种操作留下对应的行,否则我们不保证可以正确评分。
    【数据规模和约定】
    你可以认为在任何时刻,数列中至少有 1 个数。
    输入数据一定是正确的,即指定位置的数在数列中一定存在。
    50%的数据中,任何时刻数列中最多含有 30 000 个数;
    100%的数据中,任何时刻数列中最多含有 500 000 个数。
    100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。
    100%的数据中,M ≤20 000,插入的数字总数不超过 4 000 000 个,输入文件大小不超过 20MBytes。

fhptreap模版,这题好恶心


#include <cstdio>
#include <queue>
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

inline void read(int &x) {
    static char c;bool flag = 0;
    while((c=getchar())<'0'||c>'9') flag |= (c=='-');
    x=c-'0';while((c=getchar())>='0'&&c<='9') x = x*10+c-'0';
    flag?x=-x:x;
}

void pout(int x) {if(x >= 10) pout(x/10);putchar(x%10+'0');}
void out(int x) {
	if(x < 0) putchar('-'),x = -x;
	pout(x);
}

int mid_order(int o);

#define Noval  -2333333
#define N      600001
#define lh(o)  t[o].lch
#define rh(o)  t[o].rch
#define L      t[o].lch
#define R      t[o].rch
#define MP     make_pair
#define Out    mid_order(rt);putchar('\n');
typedef pair<int,int> pii;
const int inf = ~0u>>2;
inline int max(const int &x,const int &y) {return x>y ? x:y;}

struct Node {
   int lch,rch,siz,r,v;
   int rev,cov;
   int sum,lsum,rsum,maxsum;
}t[N];
int tot = 1;
int pool[N],top;

inline int New_Node(int v) {
	int o = top ? pool[top--]:++tot;
    t[o].v = v; t[o].r = rand(); t[o].siz = 1; 
    t[o].maxsum = t[o].lsum = t[o].rsum = t[o].sum = v;
    t[o].rev = 0; t[o].cov = Noval;
    t[o].lch = t[o].rch = 0;  
	return o;
}

inline void up(int o) {
   t[o].siz = t[L].siz+t[R].siz+1;
   t[o].sum = t[L].sum+t[R].sum+t[o].v;
   t[o].lsum = max(t[L].sum+t[o].v+max(0,t[R].lsum),t[L].lsum);
   t[o].rsum = max(t[R].sum+t[o].v+max(0,t[L].rsum),t[R].rsum);
   t[o].maxsum = max(0,t[L].rsum)+t[o].v+max(0,t[R].lsum);
   t[o].maxsum = max(t[o].maxsum,max(t[L].maxsum,t[R].maxsum));
}

inline void cover(int o,int val) {
	t[o].v = val;
	t[o].sum = t[o].siz * t[o].v;
	t[o].lsum = t[o].rsum = t[o].maxsum 
		               = max(t[o].sum,t[o].v);
	t[o].cov = val;
}

inline void revr(int o) {
	swap(L,R);swap(t[o].lsum,t[o].rsum); //别忘了交换l,rsum,不能 up 
	t[o].rev ^= 1;
}

inline void down(int o) {
	if(t[o].cov != Noval) {
		if(L) cover(L,t[o].cov); 
		if(R) cover(R,t[o].cov);               
		t[o].cov = Noval;
	}
	if(t[o].rev) {
		if(L) revr(L);
		if(R) revr(R); 
	    t[o].rev = 0; 
	}
}

int mer(int a,int b) {
	return !a||!b ? a^b : t[a].r<t[b].r ?
	(down(a),rh(a) = mer(rh(a),b),up(a),a):
	(down(b),lh(b) = mer(a,lh(b)),up(b),b);
}

inline void get(int &x,int &y,const pii tp) {x=tp.first;y=tp.second;}

pii spl(int o,int k) {
	if(!o) return MP(0,0);  down(o);
	int p = k-t[L].siz-1; return p>=0 ?
	(get(R,p,spl(R,p)),up(o),MP(o,p)):
	(get(p,L,spl(L,k)),up(o),MP(p,o));
}

//////////////////////////////////////////////
int rt,lrt,rrt,ttot,c,posi;

inline void Splout(int a,int b) {
	get(lrt,rt,spl(rt,a));
	get(rt,rrt,spl(rt,b));
}
inline void Merin() {rt = mer(lrt,mer(rt,rrt));}

inline void Ins_end(int &o,int v) {o = mer(o,New_Node(v));}

inline void Insert() {
    read(posi); read(ttot);  
	get(lrt,rrt,spl(rt,posi));
	read(c); rt = New_Node(c);
	for (int i = 2; i <= ttot; i++) {
	   read(c);
	   Ins_end(rt,c);
	}
	Merin();	
}

inline void recycle(int o) {
	if(!o) return;
    pool[++top] = o;
	recycle(L); recycle(R);
}

inline void Delete() {
	read(posi); read(ttot); 
	Splout(posi-1,ttot);
    recycle(rt);
	rt = mer(lrt,rrt);
}

inline void Make_same() {
	read(posi); read(ttot); read(c); 
	Splout(posi-1,ttot);
	cover(rt,c);
	Merin();
}

inline void Reverse() {
	read(posi); read(ttot);
	Splout(posi-1,ttot);
    revr(rt);
	Merin();
} 

inline void Get_sum() {
	read(posi); read(ttot);
	Splout(posi-1,ttot);
	out(t[rt].sum);putchar('\n');
	Merin();
}

inline void Max_sum() {
	out(t[rt].maxsum);putchar('\n');
}

////////////////////////////////////////////

char s[10];int m;

int main() {
//	freopen("seq2005.in","r",stdin); freopen("seq2005.out","w",stdout);
	srand(439); int n,v; 
	t[0].maxsum = t[0].lsum = t[0].rsum = -2333;t[0].cov = Noval; // 注意边界 
    read(n); read(m);
    for (int i = 1; i <= n; i++) {
    	read(v);
    	Ins_end(rt,v);
	}
	for (int i = 1; i <= m; i++) {
		scanf("%s",s);
		switch(s[0]) {
			case 'I': Insert();    break;
			case 'D': Delete();    break;
			case 'R': Reverse();   break;  
			case 'G': Get_sum();   break;
			case 'M': s[2]=='K' ? Make_same():Max_sum();
		}
	}
    return 0;
}

int mid_order(int o) {
	if(!o) return 0;
	down(o);
	mid_order(L);
	printf("%d ",t[o].v);
	mid_order(R);
	up(o);
}

猜你喜欢

转载自blog.csdn.net/qq_33831360/article/details/88400384
今日推荐