• 【bzoj1500】 noi2005—维护数列


    http://www.lydsy.com/JudgeOnline/problem.php?id=1500 (题目链接)

    题意

      要求维护数列,操作有区间删除,区间插入,区间反转,区间修改,区间求和,求最大连续子段。

    Solution

      愿有生之年再也不写splay。代码模的hzwer。

      2017.3.24:upd了一下代码。

    代码

    // baoj1500
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #define LL long long
    #define inf (1ll<<30)
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    inline int gi() {
    	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;
    }
    
    const int maxn=1000010;
    int a[maxn],fa[maxn],n,m,rt,sz;
    char ch[30];
    struct node {
    	int lx,rx,mx,val,sum,size,son[2],rev,tag;
    	int& operator [] (int x) {return son[x];}
    }tr[maxn];
    queue<int> q;
    
    void pushup(int k) {
    	int l=tr[k][0],r=tr[k][1];
    	tr[k].size=tr[l].size+tr[r].size+1;   //子树大小
    	tr[k].sum=tr[l].sum+tr[r].sum+tr[k].val;   //区间和
    	tr[k].mx=max(tr[l].mx,tr[r].mx);   //最大连续段
    	tr[k].mx=max(tr[k].mx,tr[l].rx+tr[k].val+tr[r].lx);
    	tr[k].lx=max(tr[l].lx,tr[l].sum+tr[k].val+tr[r].lx);   //左端最大区间
    	tr[k].rx=max(tr[r].rx,tr[r].sum+tr[k].val+tr[l].rx);   //右端最大区间
    }
    void pushdown(int k) {
    	int l=tr[k][0],r=tr[k][1];
    	if (tr[k].tag) {
    		tr[k].tag=tr[k].rev=0;   //赋成同一个值,反不反转都一样
    		if (l) tr[l].tag=1,tr[l].val=tr[k].val,tr[l].sum=tr[l].val*tr[l].size;
    		if (r) tr[r].tag=1,tr[r].val=tr[k].val,tr[r].sum=tr[r].val*tr[r].size;
    		if (tr[k].val>=0) {
    			if (l) tr[l].lx=tr[l].rx=tr[l].mx=tr[l].sum;
    			if (r) tr[r].lx=tr[r].rx=tr[r].mx=tr[r].sum;
    		}
    		else {
    			if (l) tr[l].lx=tr[l].rx=0,tr[l].mx=tr[l].val;
    			if (r) tr[r].lx=tr[r].rx=0,tr[r].mx=tr[r].val;
    		}
    	}
    	if (tr[k].rev) {
    		tr[k].rev^=1,tr[l].rev^=1,tr[r].rev^=1;
    		swap(tr[l].lx,tr[l].rx),swap(tr[l][0],tr[l][1]);
    		swap(tr[r].lx,tr[r].rx),swap(tr[r][0],tr[r][1]);
    	}
    }
    void rotate(int x,int &k) {
    	int y=fa[x],z=fa[y],l,r;
    	l=tr[y][1]==x;r=l^1;
    	if (y==k) k=x;
    	else tr[z][tr[z][1]==y]=x;
    	fa[tr[x][r]]=y;fa[y]=x;fa[x]=z;
    	tr[y][l]=tr[x][r];tr[x][r]=y;
    	pushup(y),pushup(x);   //注意更新顺序
    }
    void splay(int x,int &k) {
    	while (x!=k) {
    		int y=fa[x],z=fa[y];
    		if (y!=k) {
    			if ((tr[y][0]==x) ^ (tr[z][0]==y)) rotate(x,k);
    			else rotate(y,k);
    		}
    		rotate(x,k);
    	}
    }
    int find(int k,int x) {
    	pushdown(k);
    	if (tr[tr[k][0]].size+1==x) return k;
    	else if (x<=tr[tr[k][0]].size) return find(tr[k][0],x);
    	else return find(tr[k][1],x-tr[tr[k][0]].size-1);
    }
    void recycle(int k) {   //清空
    	if (tr[k][0]) recycle(tr[k][0]);
    	if (tr[k][1]) recycle(tr[k][1]);
    	q.push(k);tr[k][0]=tr[k][1]=tr[k].tag=tr[k].rev=0;   //节点回收入队,重复利用
    }
    int split(int l,int r) {   //抠出区间
    	int x=find(rt,l),y=find(rt,r+2);
    	splay(x,rt),splay(y,tr[x][1]);
    	return tr[y][0];
    }
    int query(int l,int r) {
    	return tr[split(l,r)].sum;
    }
    void modify(int l,int r,int val) {
    	int x=split(l,r),y=fa[x];
    	tr[x].val=val;tr[x].tag=1;tr[x].sum=tr[x].size*val;
    	if (val>=0) tr[x].lx=tr[x].rx=tr[x].mx=tr[x].sum;
    	else tr[x].lx=tr[x].rx=0,tr[x].mx=val;
    	pushup(y),pushup(fa[y]);
    }
    void reverse(int l,int r) {
    	int x=split(l,r),y=fa[x];
    	if (!tr[x].tag) {
    		tr[x].rev^=1;
    		swap(tr[x][0],tr[x][1]);
    		swap(tr[x].lx,tr[x].rx);
    		pushup(y),pushup(fa[y]);
    	}
    }
    void erase(int l,int r) {
    	int x=split(l,r),y=fa[x];
    	recycle(x);tr[y][0]=0;
    	pushup(y),pushup(fa[y]);
    }
    void build(int &k,int l,int r,int f) {
    	int mid=(l+r)>>1;
    	if (!q.empty()) k=q.front(),q.pop();else k=++sz;
    	tr[k].sum=tr[k].val=a[mid];fa[k]=f;
    	tr[k].lx=tr[k].rx=tr[k].mx=max(0,a[mid]);
    	if (l<mid) build(tr[k][0],l,mid-1,k);
    	if (r>mid) build(tr[k][1],mid+1,r,k);
    	pushup(k);
    }
    void insert(int k,int tot) {
    	for (int i=1;i<=tot;i++) scanf("%d",&a[i]);
    	int x,y,z;
    	build(z,1,tot,0);
    	x=find(rt,k+1),y=find(rt,k+2);   //因为有"哨兵",实际上是find k,k+1
    	splay(x,rt),splay(y,tr[x][1]);   //因为k,k+1,所以tr[y][0]为空
    	fa[z]=y;tr[y][0]=z;pushup(y),pushup(x);   //注意pushup的顺序
    }
    int main() {
    	n=gi(),m=gi();
    	tr[0].mx=a[1]=a[n+2]=-inf;
    	for (int i=1;i<=n;i++) a[i+1]=gi();
    	build(rt,1,n+2,0);
    	while (m--) {
    		int k,tot,val;scanf("%s",ch);
    		if (ch[0]!='M' || ch[2]!='X') k=gi(),tot=gi();
    		if (ch[0]=='I') insert(k,tot);
    		else if (ch[0]=='D') erase(k,k+tot-1);
    		else if (ch[0]=='M') {
    			if (ch[2]=='X') printf("%d
    ",tr[rt].mx);
    			else scanf("%d",&val),modify(k,k+tot-1,val);
    		}
    		else if (ch[0]=='R') reverse(k,k+tot-1);
    		else if (ch[0]=='G') printf("%d
    ",query(k,k+tot-1));
    	}
    	return 0;
    }

      

  • 相关阅读:
    Ubuntu包管理命令 dpkg、apt和aptitude
    Linux curses库使用
    VC皮肤库SkinSharp 1.0.6.6的使用
    HOG(方向梯度直方图)
    2014年国外发布的中国内地大学排名18强名单
    sql语句中BEGIN TRAN...COMMIT TRAN
    搜索框中“请输入搜索keyword”
    IOS基于新浪微博开放平台微博APP
    php字符串标点等字符截取不乱吗 封装方法
    谈一谈struts2和springmvc的拦截器
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/5942173.html
Copyright © 2020-2023  润新知