bzoj1500: [NOI2005]维修数列(fhq treap)

元气小坏坏 提交于 2020-11-29 04:59:46

http://www.lydsy.com/JudgeOnline/problem.php?id=1500

 

1、覆盖标记用INF表示无覆盖标记,要求可能用0覆盖

2、代表空节点的0号节点和首尾的两个虚拟节点,所有有关取max的信息全部设为负无穷,但注意不要无穷相加爆掉int

3、空间,用一个队列回收已删除的节点的编号

4、建树的时候采用的笛卡尔树的构造方式,但并没有比错误的忽略优先级的build快多少

5、手写的max快

inline int& max(int &x, int &y) { return x > y ? x : y; }

#define max(x, y) ((x) > (y) ? (x) : (y))

 

#include<queue>
#include<cstdio>
#include<cstdlib>
#include<iostream>
//#include<algorithm>
 
using namespace std;
 
#define N 500005
 
#define INF 1e9
 
int tot,root;
 
int pri[N],val[N];
int sum[N],mxr[N],mxl[N],mx[N];
int ch[N][2],siz[N];
bool rev[N];
int tag[N];
 
int pos,cnt,w;
 
int a[N];
 
queue<int>trash;
 
int st[N],top;
 
void read(int &x)
{
    x=0; int f=1; char c=getchar();
    while(!isdigit(c)) { if(c=='-') f=-1; c=getchar();}
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar();}
    x*=f;
}
 
inline int& max(int &x, int &y) { return x > y ? x : y; }
 
void update(int x)
{
    int l=ch[x][0],r=ch[x][1];
    siz[x]=siz[l]+siz[r]+1;
    sum[x]=sum[l]+sum[r]+val[x];
    mx[x]=max(mx[l],mx[r]);
    mx[x]=max(mx[x],mxr[l]+val[x]);
    mx[x]=max(mx[x],mxl[r]+val[x]);
    mx[x]=max(mx[x],mxr[l]+mxl[r]+val[x]);
    mx[x]=max(mx[x],val[x]);
    mxr[x]=max(mxr[r],sum[r]+mxr[l]+val[x]);
    mxr[x]=max(mxr[x],sum[r]+val[x]);
    mxl[x]=max(mxl[l],sum[l]+mxl[r]+val[x]);
    mxl[x]=max(mxl[x],sum[l]+val[x]);
}
 
void down(int x)
{
    if(rev[x])
    {
        int l=ch[x][0],r=ch[x][1];
        if(l)
        {
            swap(ch[l][0],ch[l][1]);
            swap(mxl[l],mxr[l]);
            rev[l]^=1;
        }
        if(r)
        {
            swap(ch[r][0],ch[r][1]);
            swap(mxl[r],mxr[r]);
            rev[r]^=1;
        }
        rev[x]^=1;
    }
    if(tag[x]!=INF)
    {
        int l=ch[x][0],r=ch[x][1];
        if(l)
        {
            val[l]=tag[x];
            sum[l]=mxl[l]=mxr[l]=mx[l]=siz[l]*tag[x];
            tag[l]=tag[x];
        }
        if(r)
        {
            val[r]=tag[x];
            sum[r]=mxl[r]=mxr[r]=mx[r]=siz[r]*tag[x];
            tag[r]=tag[x];
        }
        tag[x]=INF;
    }
}       
 
int newnode(int v)
{
    int now;
    if(!trash.empty()) now=trash.front(),trash.pop();
    else now=++tot;
    siz[now]=1;
    val[now]=v;
    pri[now]=rand();
    tag[now]=INF;
    sum[now]=mx[now]=mxl[now]=mxr[now]=v;
    rev[now]=false;
    ch[now][0]=ch[now][1]=0;
    return now;
}
 
int build(int l,int r)
{
    int now,last; top=0;
    for(int i=l;i<=r;++i)
    {
        now=newnode(a[i]);
        last=0;
        while(top && pri[st[top]]>pri[now]) 
        {
            update(st[top]);
            last=st[top--];
        }
        if(top) ch[st[top]][1]=now;
        ch[now][0]=last; st[++top]=now;
    }
    while(top) update(st[top--]);
    return st[1];
}
 
void split(int now,int p,int &x,int &y)
{
    if(!now) x=y=0;
    else
    {
        down(now);
        if(p<=siz[ch[now][0]])
        {
            y=now;
            split(ch[now][0],p,x,ch[now][0]);
        }
        else
        {
            x=now;
            split(ch[now][1],p-siz[ch[now][0]]-1,ch[now][1],y);
        }
        update(now);
    }
}
 
int merge(int x,int y)
{
    if(x) down(x);
    if(y) down(y);
    if(!x || !y) return x+y;
    if(pri[x]<pri[y])
    {
        ch[x][1]=merge(ch[x][1],y);
        update(x);
        return x;
    }
    else
    {
        ch[y][0]=merge(x,ch[y][0]);
        update(y);
        return y;
    }
}
 
int find(int k)
{
    int now=root;
    while(1)
    {
        down(now);
        if(k<=siz[ch[now][0]]) now=ch[now][0];
        else
        {
            k-=siz[ch[now][0]];
            if(k==1) return now;
            k--;
            now=ch[now][1];
        }
    }
}
     
void insert()
{
    read(pos); read(cnt);
    pos++;
    for(int i=1;i<=cnt;++i) read(a[i]);
    int rt=build(1,cnt);
    int a,b;
    split(root,pos,a,b);
    int e=merge(a,rt);
    root=merge(e,b);
}   
 
void del(int x)
{
    if(!x) return;
    trash.push(x);
    del(ch[x][0]);
    del(ch[x][1]);
}
 
void solve(int ty)
{
    read(pos); read(cnt);
    pos++;
    int a,b;
    split(root,pos+cnt-1,a,b);
    int c,d;
    split(a,pos-1,c,d);
    if(ty==1) 
    {
        del(d);
        root=merge(c,b);
        return;
    }
    if(ty==2) 
    {
        read(w);
        tag[d]=w;
        val[d]=w;
        sum[d]=mxl[d]=mxr[d]=mx[d]=siz[d]*w;
    }
    else if(ty==3) 
    {
        rev[d]^=1;
        swap(ch[d][0],ch[d][1]);
        swap(mxl[d],mxr[d]);
    }
    else if(ty==4) printf("%d\n",sum[d]);
    root=merge(merge(c,d),b);
}
 
int main()
{
    mx[0]=mxl[0]=mxr[0]=-7e8;
    int n,m;
    read(n); read(m);
    for(int i=2;i<=n+1;++i) read(a[i]);
    a[1]=a[n+2]=-7e8;
    root=build(1,n+2);
    char s[12];
    while(m--)
    {
        scanf("%s",s);
        if(s[0]=='I') insert();
        else if(s[0]=='D') solve(1);
        else if(s[2]=='K') solve(2);
        else if(s[0]=='R') solve(3);
        else if(s[0]=='G') solve(4);
        else printf("%d\n",mx[root]);
    }
}

 

1500: [NOI2005]维修数列

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 15972  Solved: 5312
[Submit][Status][Discuss]

Description

Input

输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。

Output

对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

Sample Input

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

Sample Output

-1
10
1
10

HINT

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!