【BZOJ】1500: [NOI2005]维修数列

【算法】splay

【题解】数据结构

感谢Occult的模板>_<:HYSBZ 1500 维修数列

#include<cstdio>
#include<cctype>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=5e5+10,inf=0x3f3f3f3f;
int n,m,root,a[maxn],t[maxn][2],f[maxn],A[maxn],L[maxn],R[maxn],M[maxn],sum[maxn],en[maxn],g[maxn],s[maxn];
//关系类:f父亲 t儿子 | 数值类:num值 L左起最大子段和 R右起最大子段和 M最大子段和 sum和 s结点数 | 标记类:en覆盖标记 g翻转标记
queue<int>q;
int read()
{
    char c;int s=0,t=1;
    while(!isdigit(c=getchar()))if(c==‘-‘)t=-1;
    do{s=s*10+c-‘0‘;}while(isdigit(c=getchar()));
    return s*t;
}
int Node(int fa,int num)
{
    int sz=q.front();q.pop();
    t[sz][0]=t[sz][1]=en[sz]=g[sz]=0;
    s[sz]=1;f[sz]=fa;A[sz]=L[sz]=R[sz]=M[sz]=sum[sz]=num;
    return sz;
}
void count(int x)//与线段树更新不同,记得加自身
{
    L[x]=max(L[t[x][0]],sum[t[x][0]]+A[x]+max(0,L[t[x][1]]));
    R[x]=max(R[t[x][1]],sum[t[x][1]]+A[x]+max(0,R[t[x][0]]));
    M[x]=max(0,R[t[x][0]])+A[x]+max(0,L[t[x][1]]);
    M[x]=max(M[x],max(M[t[x][0]],M[t[x][1]]));
    sum[x]=sum[t[x][0]]+A[x]+sum[t[x][1]];
    s[x]=s[t[x][0]]+1+s[t[x][1]];
}
void pushdown(int x)
{
    if(g[x])
    {
        g[t[x][0]]^=1;g[t[x][1]]^=1;
        swap(L[t[x][0]],R[t[x][0]]);
        swap(L[t[x][1]],R[t[x][1]]);
        swap(t[x][0],t[x][1]);
        g[x]=0;
    }
    if(en[x])
    {
        if(t[x][0])
        {
            en[t[x][0]]=1;
            A[t[x][0]]=A[x];
            sum[t[x][0]]=A[x]*s[t[x][0]];
            L[t[x][0]]=R[t[x][0]]=M[t[x][0]]=A[x]>0?sum[t[x][0]]:A[x];
        }
        if(t[x][1])
        {
            en[t[x][1]]=1;
            A[t[x][1]]=A[x];
            sum[t[x][1]]=A[x]*s[t[x][1]];
            L[t[x][1]]=R[t[x][1]]=M[t[x][1]]=A[x]>0?sum[t[x][1]]:A[x];
        }
        en[x]=0;
    }
}
void rotate(int x)
{
    int k=x==t[f[x]][1];
    int y=f[x];
    t[y][k]=t[x][!k];f[t[x][!k]]=y;
    if(f[y])t[f[y]][y==t[f[y]][1]]=x;f[x]=f[y];f[y]=x;
    t[x][!k]=y;
    L[x]=L[y];R[x]=R[y];M[x]=M[y];sum[x]=sum[y];s[x]=s[y];
    count(y);
}
void splay(int x,int r)
{
    for(int fa=f[r];f[x]!=fa;)//因为y被旋走了,所以要判断f[y]
    {
        if(f[f[x]]==fa){rotate(x);break;}
        int X=x==t[f[x]][1],Y=f[x]==t[f[f[x]]][1];//等号别打少……
        if(X^Y)rotate(x),rotate(x);
         else rotate(f[x]),rotate(x);
    }
}
void find(int &x,int k)
{
    for(int i=x;i;)
    {
        pushdown(i);
        if(k<=s[t[i][0]]){i=t[i][0];continue;}
        if(k==s[t[i][0]]+1){splay(i,x);x=i;break;}
        k-=s[t[i][0]]+1;i=t[i][1];//else不安全。。。
    }
}
void build(int fa,int &x,int l,int r)
{
    if(l>r)return;
    int mid=(l+r)>>1;
    x=Node(fa,a[mid]);
    build(x,t[x][0],l,mid-1);
    build(x,t[x][1],mid+1,r);
    count(x);//
}
void insert()
{
    int l=read(),k=read();
    for(int i=1;i<=k;i++)a[i]=read();
    int r;build(0,r,1,k);
    find(root,l+1);find(t[root][1],1);
    t[t[root][1]][0]=r;f[r]=t[root][1];
    count(t[root][1]);count(root);//记得count
}
void erase(int x)
{
    if(!x)return;
    q.push(x);
    erase(t[x][0]);
    erase(t[x][1]);
}
void del()
{
    int l=read(),k=read();
    find(root,l);find(t[root][1],k+1);
    erase(t[t[root][1]][0]);
    t[t[root][1]][0]=0;
    count(t[root][1]);count(root);//
}
void cover()
{
    int l=read(),k=read(),num=read();
    find(root,l);find(t[root][1],k+1);
    int y=t[t[root][1]][0];
    en[y]=1;A[y]=num;
    sum[y]=s[y]*A[y];
    L[y]=R[y]=M[y]=A[y]>0?sum[y]:A[y];
    count(t[root][1]);count(root);//
}
void round()
{
    int l=read(),k=read();
    find(root,l);find(t[root][1],k+1);
    int y=t[t[root][1]][0];
    g[y]^=1;
    swap(L[y],R[y]);
    count(t[root][1]);count(root);//
}
void getsum()
{
    int l=read(),k=read();
    find(root,l);find(t[root][1],k+1);
    printf("%d\n",sum[t[t[root][1]][0]]);
}
void getM()
{
    int sz=s[root];
    find(root,1);
    find(t[root][1],sz-1);
    printf("%d\n",M[t[t[root][1]][0]]);
}
char str[20];
int main()
{
    n=read();m=read();
    a[0]=a[n+1]=root=0;
    for(int i=1;i<=maxn;i++)q.push(i);
    L[0]=R[0]=M[0]=-inf;//使空结点干扰判断,过程中需保证任何时刻都不应修改到该点的值。
    for(int i=1;i<=n;i++)a[i]=read();
    build(0,root,0,n+1);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",str);
        if(str[2]==‘S‘)insert();
        if(str[2]==‘L‘)del();
        if(str[2]==‘K‘)cover();
        if(str[2]==‘V‘)round();
        if(str[2]==‘T‘)getsum();
        if(str[2]==‘X‘)getM();
    }
    return 0;
}

时间: 2024-10-01 21:26:50

【BZOJ】1500: [NOI2005]维修数列的相关文章

BZOJ 1500: [NOI2005]维修数列

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 12880  Solved: 4112[Submit][Status][Discuss] Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,

BZOJ 1500: [NOI2005]维修数列( splay )

splay..... ------------------------------------------------------------------------ #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> #define rep( i , n ) for( int i = 0 ; i < n ; ++

1500: [NOI2005]维修数列

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 12952  Solved: 4138[Submit][Status][Discuss] Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,

【BZOJ】1500: [NOI2005]维修数列(splay+变态题)

http://www.lydsy.com/JudgeOnline/problem.php?id=1500 模板不打熟你确定考场上调试得出来? 首先有非常多的坑点...我遇到的第一个就是,如何pushup............sad.. 写了一大串...可是感觉...写不下去了...看别人怎么写吧... orz 首先这个节点代表的这个区间我们维护mxl和mxr表示整个区间从左向右和从右向左能得到的最大序列和.. 然后我无脑不思考没有用好我们的定义,写了一大串的转移... 其实就是几个字.. vo

1500. [NOI2005]维修数列【平衡树-splay】

Description 请写一个程序,要求维护一个数列,支持以下 6 种操作: 请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格 Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目. 第2行包含N个数字,描述初始时的数列. 以下M行,每行一条命令,格式参见问题描述中的表格. 任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内. 插入的数字总数不超过4 000 000个,

HYSBZ 1500 [NOI2005]维修数列 splay

解题思路:终于把这道splay神题A掉了,splay专题也算是告一段落了,这个题主要的坑点,还是旋转和区间合并结合. 解题代码: 1 // File Name: hysbz1500.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月10日 星期五 10时41分03秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set>

BZOJ1500: [NOI2005]维修数列[splay ***]

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 12278  Solved: 3880[Submit][Status][Discuss] Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,

Splay必做题 [NOI2005]维修数列

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 6577  Solved: 1978[Submit][Status] Description Input 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格. Output 对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印

[NOI2005] 维修数列

mnesia在频繁操作数据的过程可能会报错:** WARNING ** Mnesia is overloaded: {dump_log, write_threshold},可以看出,mnesia应该是过载了.这个警告在mnesia dump操作会发生这个问题,表类型为disc_only_copies .disc_copies都可能会发生. 如何重现这个问题,例子的场景是多个进程同时在不断地mnesia:dirty_write/2 mnesia过载分析 1.抛出警告是在mnesia 增加dump