【BZOJ-3337】ORZJRY I 块状链表

3337: ORZJRY I

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 190  Solved: 50
[Submit][Status][Discuss]

Description

Jry最近做(屠)了很多数据结构题,所以想 BS你,他希望你能实现一种数据结构维护一个序列:

Input

第一行n;
第二行n个数;
第三行q,代表询问个数;
接下来q行,每行一个op,输入格式见描述。

Output

对于7≤op≤11的操作,一行输出一个答案。

Sample Input

6
5 2 6 3 1 4
15
7 2 4
8 1 3
9 2 4 5
10 1 6 4
11 2 5 4
6 1 4 7
8 1 4
5 3 4 5
2 1
1 2 8
3 3 5
4 1 5 2
9 2 5 4
10 3 6 4
11 1 6 100

Sample Output

11
4
1
4
3
0
3
12
6

HINT

n,q≤100000;
任意时刻数列中的数≤2^31-1。
0≤任意时刻数列中的数≤2^31-1。

本题共3组数据

Source

by orzjry

Solution

switch(opt)
{
  case 1: 直接分裂后插入即可  break;
  case 2: 分裂后直接删除  break;
  case 3: 分裂得到[l,r]将指向l的块指向r,l指向r指向的块,然后给[l,r]中所有块打上反转标记  break;
  case 4: 提取出[r-k,r],将这段从中删除,再整段插入到l之前  break;
  case 5: 提取[l,r],打tag标记  break;
  case 6: 提取[l,r],打del标记  break;
  case 7: 提取[l,r],扫描一遍区间中的所有块,统计sum  break;
  case 8: 同上,统计max和min,输出max-min  break;
  case 9: 二分,找到最接近它的两个,统计答案  break;
  case 10:二分,用下述方法check  break;
  case 11: 二分统计个数  break;
}

上述这些二分大都可以用upper_bound/lower_bound,注意的是Split和Merge的时候要PushDown和Update

千万不要在查询的时候PushDown...那样复杂度会炸!

Code

(本机AC,OJ  TLE)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<ctime>
using namespace std;
#define LL long long
int read()
{
    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;
}
#define MAXN 100010
int Bsize,N,Q,a[MAXN];
namespace BlockLists
{
    #define BN 5010
    struct BLNode{int next,data[1010],tag,tmp[1010],size,maxx,minn,del; LL sum; bool rev;}B[BN];
    int start,ID;
    queue<int>trash;
    inline int New() {if (trash.empty()) return ++ID; int tmp=trash.front(); trash.pop(); return tmp;}
    inline void Del(int x) {trash.push(x); B[x].next=-1; B[x].size=B[x].maxx=B[x].minn=B[x].sum=B[x].tag=B[x].rev=B[x].del=0;}
    inline int GetP(int rk) {int p; for (p=start; ~B[p].next && rk>B[p].size; p=B[p].next) rk-=B[p].size; return p;}
    inline int GetK(int rk) {int p; for (p=start; ~B[p].next && rk>B[p].size; p=B[p].next) rk-=B[p].size; return rk;}
    inline void PushDown(int x)
    {
        int sz=B[x].size; 
        if (B[x].del) {int del=B[x].del; B[x].del=0; for (int i=1; i<=sz; i++) B[x].data[i]=del; B[x].sum=sz*del;}
        if (B[x].rev) {reverse(B[x].data+1,B[x].data+sz+1); B[x].rev^=1;}
        if (B[x].tag) {int tag=B[x].tag; B[x].tag=0; for (int i=1; i<=sz; i++) B[x].data[i]+=tag; B[x].sum+=(LL)sz*tag;}
    }
    inline void Update(int x)
    {
        int sz=B[x].size; B[x].sum=0;
        for (int i=1; i<=sz; i++) B[x].sum+=B[x].data[i],B[x].tmp[i]=B[x].data[i];
        sort(B[x].tmp+1,B[x].tmp+sz+1);
        B[x].minn=B[x].tmp[1],B[x].maxx=B[x].tmp[B[x].size];
    }
    inline void Split(int pos,int rk)
    {
        PushDown(pos);
        int id=New(); for (int i=rk; i<=B[pos].size; i++) B[id].data[++B[id].size]=B[pos].data[i]; B[id].next=B[pos].next;
        B[pos].next=id; B[pos].size=max(rk-1,0);
        Update(id); Update(pos);
    }
    inline void Merge(int pos)
    {
        for ( ; ~pos; pos=B[pos].next)
            for (int suf=B[pos].next; ~suf && B[pos].size+B[suf].size<=Bsize; suf=B[suf].next)
                {
                    PushDown(pos),PushDown(suf);
                       for (int k=1; k<=B[suf].size; k++) B[pos].data[++B[pos].size]=B[suf].data[k];
                    B[pos].next=B[suf].next,Del(suf),Update(pos);
                   }
    }
    inline void Insert(int s,int x)
    {
        int now=GetP(s+1),pos=GetK(s+1); Split(now,pos);
        B[now].data[++B[now].size]=x; Update(now); Merge(now);
    }
    inline void Delete(int s)
    {
        int now=GetP(s),pos=GetK(s); PushDown(now);
        for (int i=pos+1; i<=B[now].size; i++) B[now].data[i-1]=B[now].data[i]; B[now].size--;
        Update(now),Merge(now);
    }
    inline void Prework(int l,int r,int &x,int &y)
    {
        int now1=GetP(l),pos1=GetK(l);  Split(now1,pos1);
        int now2=GetP(r+1),pos2=GetK(r+1);  Split(now2,pos2);
        x=now1,y=GetP(r);
    }
    int st[MAXN];
    inline void Rever(int l,int r)
    {
        int x,y,top=0; Prework(l,r,x,y);
        for (int i=B[x].next; ~i && i!=B[y].next; i=B[i].next) st[++top]=i,B[i].rev^=1;
        B[st[1]].next=B[y].next;
        for (int i=top; i>1; i--) B[st[i]].next=st[i-1];
        B[x].next=y; Merge(x);
    }
    inline void Move(int l,int r,int k)
    {
        int x,y,z,tmp; Prework(l,r-k,x,z); Prework(r-k+1,r,z,y);
        tmp=B[x].next; B[x].next=B[z].next,B[z].next=B[y].next,B[y].next=tmp;
        Merge(x);
    }
    inline void Add(int l,int r,int D)
    {
        int x,y; Prework(l,r,x,y);
        for (int i=B[x].next; ~i && i!=B[y].next; i=B[i].next) B[i].sum+=(LL)B[i].size*D,B[i].tag+=D;
        Merge(x);
    }
    inline void Modify(int l,int r,int val)
    {
        int x,y; Prework(l,r,x,y);
        for (int i=B[x].next; ~i && i!=B[y].next; i=B[i].next) B[i].tag=0,B[i].del=val,B[i].sum=(LL)B[i].size*val;
        Merge(x);
    }
    inline LL GetSum(int l,int r)
    {
        int x,y; LL re=0; Prework(l,r,x,y);
        for (int i=B[x].next; ~i && i!=B[y].next; i=B[i].next) re+=B[i].sum;
        Merge(x); return re;
    }
    #define INF 0x7fffffff
    inline int GetRange(int l,int r)
    {
        int x,y,maxx=-INF,minn=INF; Prework(l,r,x,y);
        for (int i=B[x].next; ~i && i!=B[y].next; i=B[i].next) 
            if (B[i].del) maxx=max(maxx,B[i].del+B[i].tag),minn=min(minn,B[i].del+B[i].tag);
                else maxx=max(maxx,B[i].maxx+B[i].tag),minn=min(minn,B[i].minn+B[i].tag);
        Merge(x); return maxx-minn;
    }
    inline int GetClose(int l,int r,int val)
    {
        int x,y,re=INF; Prework(l,r,x,y);
        for (int t,i=B[x].next; ~i && i!=B[y].next; i=B[i].next)
            if (B[i].del) re=min(re,abs(val-(B[i].del+B[i].tag)));
                else
                    {
                           t=lower_bound(B[i].tmp+1,B[i].tmp+B[i].size+1,val-B[i].tag)-B[i].tmp;
                           if (t!=B[i].size+1) re=min(re,abs(B[i].tmp[t]+B[i].tag-val));
                        if (t!=1) re=min(re,abs(val-(B[i].tmp[t-1]+B[i].tag))); 
                    }
        Merge(x); return re;
    }
    inline int GetKth(int l,int r,int k)
    {
        int x,y,t=-INF; Prework(l,r,x,y);
        for (int i=B[x].next; ~i && i!=B[y].next; i=B[i].next) t=max(t,B[i].del? B[i].del+B[i].tag:B[i].maxx+B[i].tag);
        int L=0,R=t;
        while (L<R)
            {
                int mid=((L+R)>>1)+1,re=1;
                for (int i=B[x].next; ~i && i!=B[y].next; i=B[i].next) 
                    if (B[i].del) if (B[i].del+B[i].tag<mid) re+=B[i].size; else;
                        else t=upper_bound(B[i].tmp+1,B[i].tmp+B[i].size+1,mid-1-B[i].tag)-B[i].tmp,re+=max(0,t-1);
                if (k>=re) L=mid; else R=mid-1;
            }
        Merge(x); return L;
    }
    inline int GetSmall(int l,int r,int val)
    {
        int x,y,re=0; Prework(l,r,x,y);
        for (int t,i=B[x].next; ~i && i!=B[y].next; i=B[i].next) 
            if (B[i].del) if (B[i].del+B[i].tag<val) re+=B[i].size; else;
                else t=upper_bound(B[i].tmp+1,B[i].tmp+B[i].size+1,val-B[i].tag-1)-B[i].tmp,re+=t-1;
        Merge(x); return re;
    }
    inline void Init() {start=0; ID=0; B[0].next=-1; B[0].size=0;}
}
using namespace BlockLists;
int main()
{
//    freopen("data.in","r",stdin);
//    freopen("ORZJRY.out","w",stdout);
    int N=read();
    Init();
    for (int x,i=1; i<=N; i++) x=read(),Insert(i-1,x);
    Bsize=sqrt(N+(rand()%((int)sqrt(N))) );
    Q=read();
    while (Q--)
        {
//            puts("=============================================");
            int opt=read(); int x,y,k;
//            printf("%d   :",opt);
            switch (opt)
                {
                    case 1: x=read(),k=read(),Insert(x,k); break;
                    case 2: x=read(); Delete(x); break;
                    case 3: x=read(),y=read(); Rever(x,y); break;
                    case 4: x=read(),y=read(),k=read(); Move(x,y,k); break;
                    case 5: x=read(),y=read(),k=read(); Add(x,y,k); break;
                    case 6: x=read(),y=read(),k=read(); Modify(x,y,k); break;
                    case 7: x=read(),y=read(); printf("%lld\n",GetSum(x,y)); break;
                    case 8: x=read(),y=read(); printf("%d\n",GetRange(x,y)); break;
                    case 9: x=read(),y=read(),k=read(); printf("%d\n",GetClose(x,y,k)); break;
                    case 10: x=read(),y=read(),k=read(); printf("%d\n",GetKth(x,y,k)); break;
                    case 11: x=read(),y=read(),k=read(); printf("%d\n",GetSmall(x,y,k)); break;
                }
//            puts("");
        }
    return 0;
}

char哥说的对,用数组的我,BZOJ开O2是挽救不了我的....然后我自测AC...无限TLE....

已经生无可恋了。

转载于:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5876124.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值