bzoj1251 序列终结者 splay
又写了一次splay 感觉更有体会 速度居然又卡进了首页。。
这题要注意初始值应为-inf(mx和v)
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #define rep(i,l,r) for(int i=l;i<r;i++) #define clr(a,x) memset(a,x,sizeof(a)) using namespace std; const int maxn=50050,maxm=100050,inf=0x3fffffff; int n,m; struct node*null,*pt; struct node{ node*ch[2]; int v,s,add,mx; bool rev; inline int cmp(int k) const{ k-=ch[0]->s; if(k==1) return -1; return k<=0?0:1; } inline void maintain(){ s=ch[0]->s+ch[1]->s+1; mx=max(v,max(ch[0]->mx,ch[1]->mx)); } inline void pushdown(){ if(rev){ rev=0; ch[0]->rev^=1; ch[1]->rev^=1; swap(ch[0],ch[1]); } if(add){ if(ch[0]!=null){ ch[0]->add+=add; ch[0]->v+=add; ch[0]->mx+=add; } if(ch[1]!=null){ ch[1]->add+=add; ch[1]->mx+=add; ch[1]->v+=add; } add=0; } } }; node*newnode(){ pt->ch[0]=null; pt->ch[1]=null; pt->mx=0; pt->add=0; pt->v=0; pt->s=1; pt->rev=0; return pt++; } node*root; node x[maxn]; void rotate(node*&o,int d) { node*k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o; o->maintain();k->maintain(); o=k; } void splay(node*&o,int k) { o->pushdown(); int d=o->cmp(k); if(d==-1) return; if(d==1) k-=o->ch[0]->s+1; node*p=o->ch[d]; p->pushdown(); int d2=p->cmp(k); int k2=d2?k-p->ch[0]->s-1:k; if(d2!=-1){ splay(p->ch[d2],k2); d==d2?rotate(o,d^1):rotate(o->ch[d],d); } rotate(o,d^1); } node* build(int l,int r) { if(l>=r) return null; int mid=(l+r)>>1; node*o=newnode(); if(l<mid) o->ch[0]=build(l,mid); if(mid+1<r) o->ch[1]=build(mid+1,r); o->maintain(); return o; } int read() { char c; int f=1,ans=0; c=getchar(); while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); } while(isdigit(c)){ ans=ans*10+c-'0'; c=getchar(); } return f*ans; } void init() { pt=x; null=newnode(); null->v=-inf; null->mx=-inf; null->s=0; root=build(0,n+2); } int main() { n=read(),m=read(); init(); while(m--){ int opt=read(); if(opt==1){ int l=read(),r=read(),delta=read(); splay(root,l); splay(root->ch[1],r+1-root->ch[0]->s); root->ch[1]->ch[0]->add+=delta; root->ch[1]->ch[0]->v+=delta; root->ch[1]->ch[0]->mx+=delta; }else if(opt==2){ int l=read(),r=read(); if(l==r) continue; splay(root,l); splay(root->ch[1],r+1-root->ch[0]->s); root->ch[1]->ch[0]->rev^=1; }else{ int l=read(),r=read(); splay(root,l); splay(root->ch[1],r+1-root->ch[0]->s); printf("%d\n",root->ch[1]->ch[0]->mx); } } return 0; }
1251: 序列终结者
Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 2791 Solved: 1110
[Submit][Status][Discuss]
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
1 1 3 2
1 2 4 -1
2 1 3
3 2 4
Sample Output
2
【数据范围】
N<=50000,M<=100000。
【数据范围】
N<=50000,M<=100000。