洛谷P3380:二逼平衡树 (树套树)

来源:互联网 发布:云计算培训班 编辑:程序博客网 时间:2024/05/17 23:52

题目传送门:https://www.luogu.org/problemnew/show/3380


题目分析:为什么我要把这道模板题写在博客上呢?因为我想记录一个卡常的小技巧。骗访问量

这题我是考noip之前码的,写的是坐标线段树套动态开节点的权值线段树,虽然空间是O(nlog2(n)),但实际空间并没有这么大。由于在log(n)棵线段树上同时二叉查找,时间是O(mlog2(n))的,然而被卡成了70分,跑得比Ghastlcon的log3(n)的zkw线段树+二分+Treap还慢。

多次修改后还是T3个点,我决定弃坑了。今天早上我忽然想到一个很有力的优化:如果权值线段树已经走到空节点,就不要再往下走,直接退出。结果900多ms卡过了这题QAQ。


CODE:

#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=50100;const int maxl=21;const int oo=2147483647;struct Tnode{    int sum;    Tnode *lson,*rson;} tree[maxn*maxl*maxl];Tnode *Seg[maxn<<2];Tnode *Root[maxl<<1];int cur=-1,num;struct data{    int l,r,k,val,id,Time,opt;} work[maxn*3];int temp;int a[maxn];int b[maxn<<1];int n,m;bool Comp1(data x,data y){    return x.val<y.val;}bool Comp2(data x,data y){    return x.Time<y.Time;}Tnode *New_node(){    cur++;    tree[cur].sum=0;    tree[cur].lson=tree[cur].rson=tree;    return tree+cur;}void Build(int root,int L,int R){    Seg[root]=tree;    if (L==R) return;    int mid=(L+R)>>1;    int Left=root<<1;    int Right=Left|1;    Build(Left,L,mid);    Build(Right,mid+1,R);}int Query(Tnode *root,int L,int R,int x,int y){    if ( y<L || R<x || root==tree ) return 0;//root==tree的时候退出,这是个很有力的优化!!    if ( x<=L && R<=y ) return root->sum;    int mid=(L+R)>>1;    int vl=Query(root->lson,L,mid,x,y);    int vr=Query(root->rson,mid+1,R,x,y);    return (vl+vr);}int Ask(int root,int L,int R,int x,int y,int v){    if ( y<L || R<x ) return 0;    if ( x<=L && R<=y ) return Query(Seg[root],1,temp,1,v);    int mid=(L+R)>>1;    int Left=root<<1;    int Right=Left|1;    int vl=Ask(Left,L,mid,x,y,v);    int vr=Ask(Right,mid+1,R,x,y,v);    return (vl+vr);}void Push(int root,int L,int R,int x,int y){    if ( y<L || R<x ) return;    if ( x<=L && R<=y )    {        Root[++num]=Seg[root];        return;    }    int mid=(L+R)>>1;    int Left=root<<1;    int Right=Left|1;    Push(Left,L,mid,x,y);    Push(Right,mid+1,R,x,y);}int Find(int L,int R,int Rank){    if (L==R) return L;    int Left=0,mid=(L+R)>>1;    for (int i=1; i<=num; i++) Left+=Root[i]->lson->sum;    if (Rank<=Left)    {        for (int i=1; i<=num; i++) Root[i]=Root[i]->lson;        return Find(L,mid,Rank);    }    else    {        Rank-=Left;        for (int i=1; i<=num; i++) Root[i]=Root[i]->rson;        return Find(mid+1,R,Rank);    }}void Update(Tnode *&root,int L,int R,int x,int v){    if (root==tree) root=New_node();    if (L==R)    {        root->sum+=v;        return;    }    int mid=(L+R)>>1;    if (x<=mid) Update(root->lson,L,mid,x,v);    else Update(root->rson,mid+1,R,x,v);    root->sum=root->lson->sum+root->rson->sum;}void Insert(int root,int L,int R,int x,int v){    Update(Seg[root],1,temp,v,1);    if (L==R) return;    int mid=(L+R)>>1;    int Left=root<<1;    int Right=Left|1;    if (x<=mid) Insert(Left,L,mid,x,v);    else Insert(Right,mid+1,R,x,v);}void Delete(int root,int L,int R,int x,int v){    Update(Seg[root],1,temp,v,-1);    if (L==R) return;    int mid=(L+R)>>1;    int Left=root<<1;    int Right=Left|1;    if (x<=mid) Delete(Left,L,mid,x,v);    else Delete(Right,mid+1,R,x,v);}int main(){    freopen("3380.in","r",stdin);    freopen("3380.out","w",stdout);    scanf("%d%d",&n,&m);    for (int i=1; i<=n; i++)    {        scanf("%d",&a[i]);        work[i].val=a[i];        work[i].l=i;        work[i].opt=3;    }    int x=n;    for (int i=1; i<=m; i++)    {        x++;        scanf("%d",&work[x].opt);        if (work[x].opt!=3)        {            scanf("%d%d",&work[x].l,&work[x].r);            if (work[x].opt==2) scanf("%d",&work[x].k);            else scanf("%d",&work[x].val);        }        else        {            work[x].opt=6;            scanf("%d",&work[x].l);            work[x].val=a[ work[x].l ];            x++;            work[x].opt=3;            scanf("%d",&work[x].val);            work[x].l=work[x-1].l;            a[ work[x].l ]=work[x].val;        }    }    for (int i=1; i<=x; i++) work[i].Time=i;    sort(work+1,work+x+1,Comp1);    temp=work[1].id=1;    for (int i=2; i<=x; i++)        if (work[i-1].val==work[i].val) work[i].id=temp;        else work[i].id=++temp,b[temp]=work[i].val;    sort(work+1,work+x+1,Comp2);    New_node();    Build(1,1,n);    for (int i=1; i<=x; i++)    {        if (work[i].opt==1)        {            int ans=Ask(1,1,n,work[i].l,work[i].r,work[i].id-1)+1;            printf("%d\n",ans);        }        if (work[i].opt==2)        {            num=0;            Push(1,1,n,work[i].l,work[i].r);            int ans=Find(1,temp,work[i].k);            printf("%d\n",b[ans]);        }        if (work[i].opt==3) Insert(1,1,n,work[i].l,work[i].id);        if (work[i].opt==4)        {            int ans;            int Rank=Ask(1,1,n,work[i].l,work[i].r,work[i].id-1);            if (!Rank) ans=-oo;            else            {                num=0;                Push(1,1,n,work[i].l,work[i].r);                ans=b[ Find(1,temp,Rank) ];            }            printf("%d\n",ans);        }        if (work[i].opt==5)        {            int ans;            int Rank=Ask(1,1,n,work[i].l,work[i].r,work[i].id);            if (Rank==work[i].r-work[i].l+1) ans=oo;            else            {                Rank++;                num=0;                Push(1,1,n,work[i].l,work[i].r);                ans=b[ Find(1,temp,Rank) ];            }            printf("%d\n",ans);        }        if (work[i].opt==6) Delete(1,1,n,work[i].l,work[i].id);    }    //printf("%d\n",sizeof(tree)>>20);    return 0;}
原创粉丝点击