zoukankan      html  css  js  c++  java
  • [BZOJ 1058] 报表统计

    Link:

    BZOJ 1058 传送门

    Solution:

    为了这道题今天下午一直都在和常数大战……

    1、对于询问1,我们记录每个数末位置的数$T[i]$和初始位置$S[i]$

    用平衡树维护所有差值,对于操作$i,k$:删除$S[i+1]-T[i]$,增加$x-T[i]$和$x-S[i+1]$

    2、对于询问2,用平衡树记录所有值,每次找到$k$的前驱和后继更新$mn$就好了

    当然以上都可以不用手写平衡树,用$multiset$和$priority\_ queue$可水过

    但我如此耿直的人还是用结构体写了两个$Splay$分别维护两个询问

    下面总结下出的各种锅和常数优化细节吧:

    1、补锅匠系列:

    (1)范围要开到$2*n$,毕竟每次会新加进一个数

    这时显示的居然是$TLE$不是$RE$?以后要注意……

    (2)对于询问2在查找前驱后继时要包含与查找数相同的数

    此时不是严格小于/大于啊……

    2、卡常系列:

    (1)基础的IO,$register$,$inline$

    (2)进行任何操作后最好都$Splay$一遍来保证复杂度!

    (3)如果$mn=0$时直接将后面的更新剪枝,好像对$Luogu$上的数据很有效……

    (4)尽量少外界调用结构体内函数

    卡常卡到最后还是只过了$Luogu$,$BZOJ$过不去啊……

    但好像$BZOJ$数据加强了,黄学长的标程也T了……

    最后发现别人用$Treap$写比我的快10倍?以后还是少写$Splay$吧

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;//注意MAXN要开到1e6 
    const int MAXN=1e6+50,INF=0x3f3f3f3f;
    char s[20];int n,m,dat[MAXN],S[MAXN],T[MAXN],mn=INF;
    
    inline int read()
    {
        char ch;int num,f=0;
        while(!isdigit(ch=getchar())) f|=(ch=='-');
        num=ch-'0';
        while(isdigit(ch=getchar())) num=num*10+ch-'0';
        return f?-num:num;
    }
    inline void write(int x)
    {
        if(x<0) putchar('-'),x=-x;
        if(x>9) write(x/10);
        putchar(x%10+'0');
    }
    
    struct splay
    {
        int rt,sz[MAXN],cnt[MAXN],val[MAXN],f[MAXN],ch[MAXN][2],tot;
        inline void pushup(int x)
        {sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x];}
        inline void Rotate(int x)
        {
            int y=f[x],z=f[y],k=(ch[y][1]==x);
            ch[z][ch[z][1]==y]=x;f[x]=z;
            ch[y][k]=ch[x][k^1];f[ch[x][k^1]]=y;
            ch[x][k^1]=y;f[y]=x;
            pushup(x);pushup(y);
        }
        inline void Splay(int x,int up)
        {
            while(f[x]!=up)
            {
                int y=f[x],z=f[y];
                if(z!=up) (ch[y][1]==x)^(ch[z][1]==y)?Rotate(x):Rotate(y);
                Rotate(x);
            }
            if(!up) rt=x;
        }
        inline void Insert(int x)
        {
            int k=rt,anc=0;
            while(k&&x!=val[k]) 
                anc=k,k=ch[k][x>val[k]];
            
            if(k) {cnt[k]++;Splay(k,0);return;}
            k=++tot;
            if(anc) ch[anc][x>val[anc]]=k;
            ch[k][0]=ch[k][1]=0;
            sz[k]=cnt[k]=1;f[k]=anc;val[k]=x;
            Splay(k,0);
        }
        inline void Find(int x)
        {
            int k=rt;
            while(ch[k][x>val[k]]&&x!=val[k])
                k=ch[k][x>val[k]];
            Splay(k,0);
        }
        inline int Kth(int x)
        {
            int k=rt;
            while(true)
            {
                if(sz[ch[k][0]]+cnt[k]<x)
                    x-=sz[ch[k][0]]+cnt[k],k=ch[k][1];
                else if(sz[ch[k][0]]>=x) k=ch[k][0];
                else return k;
            }
        }
        inline int Next(int x,int flag)
        {
            Find(x);int k=rt;
            if((val[k]<x&&!flag)||(val[k]>x&&flag)) return k;
            k=ch[k][flag];
            while(ch[k][flag^1]) k=ch[k][flag^1];
            Splay(k,0);return k;
        }
        inline int Next2(int x,int flag)
        {
            Find(x);int k=rt;
            if((val[k]<=x&&!flag)||(val[k]>=x&&flag)) return k;
            k=ch[k][flag];
            while(ch[k][flag^1]) k=ch[k][flag^1];
            Splay(k,0);return k;
        }
        inline void Delete(int x)
        {
            int nxt=Next(x,1),lst=Next(x,0);
            Splay(lst,0);Splay(nxt,lst);
            if(cnt[ch[nxt][0]]>1)
                cnt[ch[nxt][0]]--,Splay(ch[nxt][0],0);
            else ch[nxt][0]=0;
        }
        inline void push(int x)
        {//调用结构体函数的次数越少越好,因此push放里面快 
            if(!mn) return;
            int nxt=Next2(x,1),lst=Next2(x,0);
            mn=min(mn,min(abs(val[nxt]-x),abs(val[lst]-x)));
            Insert(x);
        }
    }all,adj;
    
    int main()
    {
        n=read();m=read();
        all.Insert(INF);all.Insert(-INF);
        adj.Insert(INF);adj.Insert(-INF);
        for(register int i=1;i<=n;i++) 
            dat[i]=read(),all.push(dat[i]),S[i]=T[i]=dat[i];
        for(register int i=2;i<=n;i++) adj.Insert(abs(dat[i]-dat[i-1]));
        
        while(m--)
        {
            int x,y;scanf("%s",s);
            if(s[0]=='I')
            {
                x=read();y=read();
                if(x!=n) adj.Delete(abs(S[x+1]-T[x]));
                adj.Insert(abs(y-T[x]));
                adj.Insert(abs(y-S[x+1]));
                all.push(y);T[x]=y;
            }
            else if(s[4]=='G') write(adj.val[adj.Kth(2)]),putchar('
    ');
            else write(mn),putchar('
    ');
        }
        return 0;
    }
  • 相关阅读:
    javascript js 内存泄露
    javascript js 内存泄露工具使用
    逻辑运算符及按位或与非比较难理解先放着87
    //测试全局变量及局部变量的输出结果的异同
    域名被墙原因
    编写转义字符:78页
    1.1-java创建包和类的方法
    浏览器方法及代码打包成APP的
    一个简单的jsp+servlet实例,实现简单的登录
    LeetCode.985-查询后偶数的总和(Sum of Even Numbers After Queries)
  • 原文地址:https://www.cnblogs.com/newera/p/9368706.html
Copyright © 2011-2022 走看看