bzoj3110(线段树套线段树、树状数组套线段树)

http://www.lydsy.com/JudgeOnline/problem.php?id=3110
题意:
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

tip:

线段树套线段树,外面是权值,每个节点上的线段树是位置,
比如,如果在1~4位置加入5 就是把整个线段树中有5的log个节点,
每个节点的1~4这log区间上++。。。。
然后每次询问的时候,二分答案,
比如权值二分到3就是求1~3中有多少个在询问的区间里,还是log个节点,
每个节点跑log个得到对应区间上的个数总和

这样会tle&& mle,代码如下:

/*
线段树套线段树,外面是权值,每个节点上的线段树是位置,
比如,如果在1~4位置加入5 就是把整个线段树中有5的log个节点,
每个节点的1~4这log区间上++。。。。
然后每次询问的时候,二分答案,
比如权值二分到3就是求1~3中有多少个在询问的区间里,还是log个节点,
每个节点跑log个得到对应区间上的个数总和

*/

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long LL;
const int maxn = 3e7+10;
const int maxm = 50000*4+10;
int root[maxm],N,Q;
struct pos_Tree{
    int lon,ron,add;
    unsigned int _size;
    void init(){
        lon = ron  = add = _size = 0;
    }
};

class segment_tree{
public:
    pos_Tree tree[maxn];LL cnt;
    void push_down(int k,int m,int l,int r){
        if(tree[k].add == 0)    return ;
        if(tree[k].lon == 0){
            cnt++;tree[k].lon = cnt;//tree[cnt].l = l;tree[cnt].r = (l+r)/2;
            tree[cnt]._size = (m-(m/2))*tree[k].add;tree[cnt].add = tree[k].add;
        }
        else    tree[tree[k].lon]._size +=(m-(m/2))*tree[k].add,tree[tree[k].lon].add += tree[k].add;
        if(tree[k].ron == 0){
            cnt++;tree[k].ron = cnt;//tree[cnt].l = (l+r)/2+1;tree[cnt].r = r;
            tree[cnt]._size = (m/2)*tree[k].add;tree[cnt].add = tree[k].add;
        }
        else    tree[tree[k].ron]._size +=(m/2)*tree[k].add,tree[tree[k].ron].add += tree[k].add;
        tree[k].add = 0;
    }
    void push_up(int k,int ln,int rn){
        tree[k]._size = tree[ln]._size+tree[rn]._size;
    }
    void _insert(int &k,int L,int R,int l,int r,int rt){
        if(k == 0){
            cnt++;tree[cnt].init();k = cnt;//tree[k].l = l;tree[k].r = r;
        }
        if(L <= l && R >= r){
            tree[k].add++;tree[k]._size += r-l+1;
            return ;
        }
        push_down(k,r-l+1,l,r);
        int m = (l+r)>>1;
        if(m >= L)  _insert(tree[k].lon,L,R,lson);
        if(m < R)   _insert(tree[k].ron,L,R,rson);
        push_up(k,tree[k].lon,tree[k].ron);
    }
    LL query(int k,int L,int R,int l,int r,int rt){
        if(l >= L && r <= R){
            return tree[k]._size;
        }
        push_down(k,r-l+1,l,r);
        //cout <<" k = "<<k<<endl;
        int m = (l+r)/2;
        LL ans = 0;
        if(m >= L && tree[k].lon)  ans += query(tree[k].lon,L,R,lson);
        if(m < R && tree[k].ron)   ans += query(tree[k].ron,L,R,rson);
        return ans;
    }
}pos_tree;//区间线段树

void build(int l,int r,int rt){
    root[rt] = 0;
    if(l == r)  return ;
    int m = (l+r)>>1;
    build(lson);
    build(rson);
}

void val_insert(int a,int b,int pos,int l,int r,int rt){
    if(pos >= l && pos <= r){
        pos_tree._insert(root[rt],a,b,1,N,1);
    }
    if(l == r)   return ;
    int m = (l+r)>>1;
    if(pos <= m)    val_insert(a,b,pos,lson);
    else    val_insert(a,b,pos,rson);
}

int _in(int mid,int l,int r,int rt){
    if(l == r && l == mid)  return root[rt];
    int m = (l+r)>>1;
    if(mid <= m)  return _in(mid,lson);
    else    return _in(mid,rson);

}

LL check(int L,int R,int posa,int posb,int l,int r,int rt){
    if(L <= l && R >= r){
        if(root[rt] == 0)   return 0;
        LL ans = pos_tree.query(root[rt],posa,posb,1,N,1);
        return ans ;
    }
    LL ans = 0;
    int m = (l+r)>>1;
    if(m >= L)  ans += check(L,R,posa,posb,lson);
    if(m < R)   ans += check(L,R,posa,posb,rson);
    return ans;
}

int bs(int posa,int posb,int c){
    int l = 1,r = N,ans = 100000000;
    while(l <= r){
        int mid = (l+r)>>1;
        LL pp = check(1,mid,posa,posb,1,N,1);
        if( pp >= c){//1~mid权值中到了c个就是可能得解,多了就缩小范围
            if(_in(mid,1,N,1))//mid是否是出现了得权值
                ans = min(ans,mid);
            r = mid-1;
        }
        else    l = mid+1;
    }
    return ans;
}
int op,a,b,c;
void sov(){
    pos_tree.cnt = 0;
    for(int i = 1;  i<= Q ; i++){
        scanf("%d",&op);
        if(op == 1){
            scanf("%d%d%d",&a,&b,&c);
            if(a > b)   swap(a,b);
            c = N-c+1;
            val_insert(a,b,c,1,N,1);
        }
        else{
            scanf("%d%d%d",&a,&b,&c);
            if(a > b)   swap(a,b);
            printf("%d\n",N-bs(a,b,c)+1);
        }
    }
}

int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    while(~scanf("%d%d",&N,&Q)){
        build(1,N,1);
        sov();
    }
    return 0;
}
/*
7 100
1 1 5 2
1 2 7 3
1 3 5 2
1 1 1 1
2 1 3 2
2 1 3 3
2 1 3 7
2 1 7 5
2 1 7 7
2 2 3 2
2 1 1 1
2 1 1 2
2 3 5 3
2 3 4 5
2 1 5 2
2 2 7 2
2 3 5 2
2 2 2 1
*/

tle版本(树状数组套线段树):

改成树状数组,mle问题解决,时间复杂度仍然有logloglog

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long LL;
const int maxn = 3e7+10;
const int maxm = 50000+10;
int root[maxm],N,Q;
struct pos_Tree{
    int lon,ron,add;
    unsigned int _size;
    void init(){
        lon = ron  = add = _size = 0;
    }
};

class segment_tree{
public:
    pos_Tree tree[maxn];LL cnt;
    void push_down(int k,int m,int l,int r){
        if(tree[k].add == 0)    return ;
        if(tree[k].lon == 0){
            cnt++;tree[k].lon = cnt;//tree[cnt].l = l;tree[cnt].r = (l+r)/2;
            tree[cnt]._size = (m-(m/2))*tree[k].add;tree[cnt].add = tree[k].add;
        }
        else    tree[tree[k].lon]._size +=(m-(m/2))*tree[k].add,tree[tree[k].lon].add += tree[k].add;
        if(tree[k].ron == 0){
            cnt++;tree[k].ron = cnt;//tree[cnt].l = (l+r)/2+1;tree[cnt].r = r;
            tree[cnt]._size = (m/2)*tree[k].add;tree[cnt].add = tree[k].add;
        }
        else    tree[tree[k].ron]._size +=(m/2)*tree[k].add,tree[tree[k].ron].add += tree[k].add;
        tree[k].add = 0;
    }
    void push_up(int k,int ln,int rn){
        tree[k]._size = tree[ln]._size+tree[rn]._size;
    }
    void _insert(int &k,int L,int R,int l,int r,int rt){
        if(k == 0){
            cnt++;tree[cnt].init();k = cnt;//tree[k].l = l;tree[k].r = r;
        }
        if(L <= l && R >= r){
            tree[k].add++;tree[k]._size += r-l+1;
            return ;
        }
        push_down(k,r-l+1,l,r);
        int m = (l+r)>>1;
        if(m >= L)  _insert(tree[k].lon,L,R,lson);
        if(m < R)   _insert(tree[k].ron,L,R,rson);
        push_up(k,tree[k].lon,tree[k].ron);
    }
    LL query(int k,int L,int R,int l,int r,int rt){
        if(l >= L && r <= R){
            return tree[k]._size;
        }
        push_down(k,r-l+1,l,r);
        //cout <<" k = "<<k<<endl;
        int m = (l+r)/2;
        LL ans = 0;
        if(m >= L && tree[k].lon)  ans += query(tree[k].lon,L,R,lson);
        if(m < R && tree[k].ron)   ans += query(tree[k].ron,L,R,rson);
        return ans;
    }
}pos_tree;//Çø¼äÏ߶ÎÊ÷

int lowbit(int x){
    return x&(-x);
}

void add(int pos,int a,int b){
    for(int i = pos ; i <= N ;i += lowbit(i)){
        pos_tree._insert(root[i],a,b,1,N,1);
    }
}

LL check(int pos,int posa,int posb){
    LL sum = 0;
    for(int i = pos; i>0 ;i-=lowbit(i)){
        sum += pos_tree.query(root[i],posa,posb,1,N,1);
    }
    return sum;
}

int bs(int posa,int posb,int k){
    int l = 1,r = N;
    while(l <= r){
        int mid = (l+r)>>1;
        LL cm = check(mid,posa,posb);//1~mid
        LL cm1 = check(mid-1,posa,posb);//1~mid-1
        if(cm >= k &&  cm1 < k){
            return mid;
        }
        else if(cm >= k)  r = mid-1;
        else    l = mid+1;  //cm<k&&cm1<k

    }
}
int op,a,b,c;
void sov(){
    pos_tree.cnt = 0;
    for(int i = 1;  i<= Q ; i++){
        scanf("%d",&op);
        if(op == 1){
            scanf("%d%d%d",&a,&b,&c);
            c = N-c+1;
            if(a > b)   swap(a,b);
            add(c,a,b);
        }
        else{
            scanf("%d%d%d",&a,&b,&c);
            if(a > b)   swap(a,b);
            printf("%d\n",N-bs(a,b,c)+1);
        }
    }
}



int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    while(~scanf("%d%d",&N,&Q)){

        sov();
    }
}

ac版本:

超时?不用二分答案,在线段树上,直接判断大的数够不够,不够的话,往左跑看加上多少左边的可以到达要求个,够的话就往右递归,看最小的范围(l==r)时候,ac代码:

/*
线段树套线段树,外面是权值,每个节点上的线段树是位置,
比如,如果在1~4位置加入5 就是把整个线段树中有5的log个节点,
每个节点的1~4这log区间上++。。。。
然后每次询问的时候,
每个节点跑log个得到对应区间上的个数总和

*/

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long LL;
const int maxn = 3e7+10;
const int maxm = 50000*4+10;
int root[maxm],N,Q;
struct pos_Tree{
    int lon,ron,add;
    unsigned int _size;
    void init(){
        lon = ron  = add = _size = 0;
    }
};

class segment_tree{
public:
    pos_Tree tree[maxn];LL cnt;
    void push_down(int k,int m,int l,int r){
        if(tree[k].add == 0)    return ;
        if(tree[k].lon == 0){
            cnt++;tree[k].lon = cnt;//tree[cnt].l = l;tree[cnt].r = (l+r)/2;
            tree[cnt]._size = (m-(m/2))*tree[k].add;tree[cnt].add = tree[k].add;
        }
        else    tree[tree[k].lon]._size +=(m-(m/2))*tree[k].add,tree[tree[k].lon].add += tree[k].add;
        if(tree[k].ron == 0){
            cnt++;tree[k].ron = cnt;//tree[cnt].l = (l+r)/2+1;tree[cnt].r = r;
            tree[cnt]._size = (m/2)*tree[k].add;tree[cnt].add = tree[k].add;
        }
        else    tree[tree[k].ron]._size +=(m/2)*tree[k].add,tree[tree[k].ron].add += tree[k].add;
        tree[k].add = 0;
    }
    void push_up(int k,int ln,int rn){
        tree[k]._size = tree[ln]._size+tree[rn]._size;
    }
    void _insert(int &k,int L,int R,int l,int r,int rt){
        if(k == 0){
            cnt++;tree[cnt].init();k = cnt;//tree[k].l = l;tree[k].r = r;
        }
        if(L <= l && R >= r){
            tree[k].add++;tree[k]._size += r-l+1;
            return ;
        }
        push_down(k,r-l+1,l,r);
        int m = (l+r)>>1;
        if(m >= L)  _insert(tree[k].lon,L,R,lson);
        if(m < R)   _insert(tree[k].ron,L,R,rson);
        push_up(k,tree[k].lon,tree[k].ron);
    }
    LL query(int k,int L,int R,int l,int r,int rt){
        if(l >= L && r <= R){
            return tree[k]._size;
        }
        push_down(k,r-l+1,l,r);
        //cout <<" k = "<<k<<endl;
        int m = (l+r)/2;
        LL ans = 0;
        if(m >= L && tree[k].lon)  ans += query(tree[k].lon,L,R,lson);
        if(m < R && tree[k].ron)   ans += query(tree[k].ron,L,R,rson);
        return ans;
    }
}pos_tree;//区间线段树

void build(int l,int r,int rt){
    root[rt] = 0;
    if(l == r)  return ;
    int m = (l+r)>>1;
    build(lson);
    build(rson);
}

void val_insert(int a,int b,int pos,int l,int r,int rt){
    if(pos >= l && pos <= r){
        pos_tree._insert(root[rt],a,b,1,N,1);
    }
    if(l == r)   return ;
    int m = (l+r)>>1;
    if(pos <= m)    val_insert(a,b,pos,lson);
    else    val_insert(a,b,pos,rson);
}


LL check(int posa,int posb,int num,int l,int r,int rt){
    if(l == r) return l;
    int m = (l+r)>>1,ans;
    LL n1 = (root[rt*2+1] == 0)?0:pos_tree.query(root[rt*2+1],posa,posb,1,N,1);
    if(n1 < num)    ans = check(posa,posb,num-n1,lson);
    else   ans = check(posa,posb,num,rson);
    return ans;
}


int op,a,b,c;
void sov(){
    pos_tree.cnt = 0;
    for(int i = 1;  i<= Q ; i++){
        scanf("%d",&op);
        if(op == 1){
            scanf("%d%d%d",&a,&b,&c);
            if(a > b)   swap(a,b);
            val_insert(a,b,c,1,N,1);
        }
        else{
            scanf("%d%d%d",&a,&b,&c);
            if(a > b)   swap(a,b);
            printf("%d\n",check(a,b,c,1,N,1));
        }
    }
}

int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    while(~scanf("%d%d",&N,&Q)){
        build(1,N,1);
        sov();
    }
    return 0;
}
/*
7 100
1 1 5 2
1 2 7 3
1 3 5 2
1 1 1 1
2 1 3 2
2 1 3 3
2 1 3 7
2 1 7 5
2 1 7 7
2 2 3 2
2 1 1 1
2 1 1 2
2 3 5 3
2 3 4 5
2 1 5 2
2 2 7 2
2 3 5 2
2 2 2 1
*/
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值