bzoj 3100 K大数查询 树套树

来源:互联网 发布:万能数据恢复破解版 编辑:程序博客网 时间:2024/05/26 08:41

外层权值线段树,对于每个权值线段树节点,建立区间线段树。但是内层这样普通建树会TLE&&MLE。仔细想会发现,区间线段树不用都建出来,用到哪个点就开哪一个点,每次操作最多经过logn个权值线段树节点,访问每个权值线段树节点时,最多修改logn个区间线段树节点,所以区间线段树总节点个数nlog²n。注意longlong。

#include<iostream>#include<cstdio>#include<algorithm>#define LL long long#define ls tree[x].ch[0]#define rs tree[x].ch[1]using namespace std;int n,m,len;void read(int &a){    int h=1;a=0;    char c=getchar();    while(c<'0'||c>'9')    {        if(c=='-') h=-1;        c=getchar();    }    while(c>='0'&&c<='9')    {        a*=10;a+=c-'0';        c=getchar();    }a*=h;}int tot;struct xds{    int ch[2];    LL cnt;    int lazy;}tree[15000000];int L,R;void spread(int x,int l,int r){    if(tree[x].lazy)    {        int mid=(l+r)>>1;        if(!ls) ls=++tot;        tree[ls].cnt+=(mid-l+1)*tree[x].lazy;        tree[ls].lazy+=tree[x].lazy;        if(!rs) rs=++tot;        tree[rs].cnt+=(r-mid)*tree[x].lazy;        tree[rs].lazy+=tree[x].lazy;        tree[x].lazy=0;    }}void up(int x){tree[x].cnt=tree[ls].cnt+tree[rs].cnt;}void add(int x,int l,int r){    if(l>=L&&r<=R)    {        tree[x].cnt+=r-l+1;        tree[x].lazy++;        return ;    }    if(!ls) ls=++tot;    if(!rs) rs=++tot;    spread(x,l,r);    int mid=(l+r)>>1;    if(mid>=L)add(ls,l,mid);    if(mid<R) add(rs,mid+1,r);    up(x);}struct qzs{    int rt;}tr[400005];void insert(int x,int l,int r,int c){    if(!tr[x].rt) tr[x].rt=++tot;    add(tr[x].rt,1,n);    if(l==r) return ;    int mid=(l+r)>>1;    if(c<=mid) insert(x<<1,l,mid,c);    else insert(x<<1|1,mid+1,r,c);}LL ask(int x,int l,int r){    if(!x) return 0;    if(l>=L&&r<=R)        return tree[x].cnt;    int mid=(l+r)>>1;    LL ans=0;    spread(x,l,r);    if(mid>=L) ans+=ask(tree[x].ch[0],l,mid);    if(mid<R)  ans+=ask(tree[x].ch[1],mid+1,r);    return ans;}int Ask(int x,int l,int r,LL k){    if(l==r) return l;    int mid=(l+r)>>1;    LL cnt=ask(tr[x<<1|1].rt,1,n);    if(cnt<k)        return Ask(x<<1,l,mid,k-cnt);    return Ask(x<<1|1,mid+1,r,k);}int main(){    scanf("%d%d",&n,&m);    int op,a,b,c;    len=2*n+1;    for(int i=1;i<=m;i++)    {        read(op);read(a);        read(b);read(c);        L=a,R=b;        if(op==1)            insert(1,1,len,c+n+1);        if(op==2)            printf("%d\n",Ask(1,1,len,c)-n-1);    }}
1 0
原创粉丝点击