离线专题学习

来源:互联网 发布:成本数据分析 编辑:程序博客网 时间:2024/05/22 18:22

hdu 4288
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4288
这题是往一个升序的集合里面加数字或者是减数字,然后求集合里面的一个值

1ikai[i%5=3]
这样这个式子,这题前面应该也讲过,就是先离线存取所有的操作,并且把数字离散化,然后用线段树维护,每个节点维护两个值,一个是num表示这会这个节点里面插了多少个数字,另一个是sum[i][5],表示这个节点里存的数字的下标i模5的不同值的和,然后更新的时候就是,如果是插入,就+a[i],删除就是a[i],然后如果是求和,就是sum[1][2],更新的时候就是考虑
sum[rt][i]=sum[lrt][i]+sum[rrt][5((num[lrt]i1)%5+5)%51]
这样就行了呢。具体sum[rrt]那边怎么算的自己想一下就好叻


#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker,"/STACK:102400000,102400000")using namespace std;#define   MAX           100005#define   MAXN          500005#define   maxnode       105#define   sigma_size    2#define   lson          l,m,rt<<1#define   rson          m+1,r,rt<<1|1#define   lrt           rt<<1#define   rrt           rt<<1|1#define   middle        int m=(r+l)>>1#define   LL            long long#define   ull           unsigned long long#define   mem(x,v)      memset(x,v,sizeof(x))#define   lowbit(x)     (x&-x)#define   pii           pair<int,int>#define   bits(a)       __builtin_popcount(a)#define   mk            make_pair#define   limit         10000//const int    prime = 999983;const int    INF   = 0x3f3f3f3f;const LL     INFF  = 0x3f3f;const double pi    = acos(-1.0);const double inf   = 1e18;const double eps   = 1e-9;const LL     mod   = 1e9+7;const ull    mx    = 1333333331;/*****************************************************/inline void RI(int &x) {      char c;      while((c=getchar())<'0' || c>'9');      x=c-'0';      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';}/*****************************************************/char op[MAX][10];int a[MAX];int b[MAX];LL sum[MAX<<2][5];int num[MAX<<2];void build(int l,int r,int rt){    num[rt]=0;    for(int i=0;i<5;i++) sum[rt][i]=0;    if(l==r) return;    middle;    build(lson);    build(rson);}void pushup(int rt){    for(int i=0;i<5;i++)        sum[rt][i]=sum[lrt][i]+sum[rrt][5-((num[lrt]-i-1)%5+5)%5-1];}void update(int l,int r,int rt,int pos,int d,int v){    num[rt]+=v;    if(l==r){        sum[rt][0]+=d;        return;    }    middle;    if(pos<=m) update(lson,pos,d,v);    else update(rson,pos,d,v);    pushup(rt);}int main(){    //freopen("test.txt","r",stdin);    int n;    while(~scanf("%d",&n)){        int tmp=0;        for(int i=0;i<n;i++){            scanf("%s",op[i]);            if(op[i][0]!='s'){                scanf("%d",&a[i]);                b[tmp++]=a[i];            }        }        build(1,n,1);        sort(b,b+tmp);        int tot=unique(b,b+tmp)-b;        for(int i=0;i<n;i++){            int pos=lower_bound(b,b+tot,a[i])-b+1;            if(op[i][0]=='a') update(1,n,1,pos,a[i],1);            else if(op[i][0]=='d') update(1,n,1,pos,-a[i],-1);            else printf("%I64d\n",sum[1][2]);        }    }    return 0;}

hdu 4417
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4417
这题问你区间里比H小的数字有多少个,也是离线搞辣,因为H很大,首先要离散化,之后就是把区间按照区间的高度从小到大排序,然后把符合的放进线段树里面,然后区间查询就可以了辣


代码:

#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker,"/STACK:102400000,102400000")using namespace std;#define   MAX           100005#define   MAXN          500005#define   maxnode       105#define   sigma_size    2#define   lson          l,m,rt<<1#define   rson          m+1,r,rt<<1|1#define   lrt           rt<<1#define   rrt           rt<<1|1#define   middle        int m=(r+l)>>1#define   LL            long long#define   ull           unsigned long long#define   mem(x,v)      memset(x,v,sizeof(x))#define   lowbit(x)     (x&-x)#define   pii           pair<int,int>#define   bits(a)       __builtin_popcount(a)#define   mk            make_pair#define   limit         10000//const int    prime = 999983;const int    INF   = 0x3f3f3f3f;const LL     INFF  = 0x3f3f;const double pi    = acos(-1.0);const double inf   = 1e18;const double eps   = 1e-9;const LL     mod   = 1e9+7;const ull    mx    = 1333333331;/*****************************************************/inline void RI(int &x) {      char c;      while((c=getchar())<'0' || c>'9');      x=c-'0';      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';}/*****************************************************/struct num{    int a,pos;    bool operator < (const num &b) const{        return a<b.a;    }}pp[MAX];struct Node{    int l,r,h,id,ans;}p[MAX];bool cmp1(Node a,Node b){    return a.h<b.h;}bool cmp2(Node a,Node b){    return a.id<b.id;}int sum[MAX<<2];void build(int l,int r,int rt){    sum[rt]=0;    if(l==r) return ;    middle;    build(lson);    build(rson);}void pushup(int rt){    sum[rt]=sum[lrt]+sum[rrt];}void update(int l,int r,int rt,int pos){    if(l==r){        sum[rt]++;        return;    }    middle;    if(pos<=m) update(lson,pos);    else update(rson,pos);    pushup(rt);}int query(int l,int r,int rt,int L,int R){    if(L<=l&&r<=R) return sum[rt];    middle;    int ans=0;    if(L<=m) ans+=query(lson, L,R);    if(R>m) ans+=query(rson,L,R);    return ans;}int main(){    //freopen("test.txt","r",stdin);    int t,kase=0;    cin>>t;    while(t--){        int n,m;        cin>>n>>m;        for(int i=0;i<n;i++){            int a;            scanf("%d",&a);            pp[i]=(num){a,i+1};        }        sort(pp,pp+n);        for(int i=0;i<m;i++){            int l,r,h;            scanf("%d%d%d",&l,&r,&h);            p[i]=(Node){l+1,r+1,h,i,0};        }        sort(p,p+m,cmp1);        int ret=0;        build(1,n,1);        for(int i=0;i<m;i++){            while(pp[ret].a<=p[i].h&&ret<n){                update(1,n,1,pp[ret].pos);                ret++;            }            p[i].ans=query(1,n,1,p[i].l,p[i].r);        }        sort(p,p+m,cmp2);        kase++;        printf("Case %d:\n",kase);        for(int i=0;i<m;i++) printf("%d\n",p[i].ans);    }    return 0;}

hdu 3874
http://acm.hdu.edu.cn/showproblem.php?pid=3874
题意:求解区间内不重复数字的和
题解:这题莫队随手秒杀,但是要好好用离线线段树的方法解决,让我想了挺久,首先我们要处理出来每个位置的数字,往前最近的一个和它相同的数字在哪个位置,然后区间按照右端点排序,然后先把所有数字都插进线段树,如果此时在i,那就删除pre[i]位置的这个数字,然后在i位置插入这个数字。
查询的时候右端点从右往左扫过来,假设此时在i位置,已经超出这个区间右端点,则在pre[i]的位置加上这个值,然后区间查询(保证此时i不在这个区间内)


代码:

#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;#define   MAX           50005#define   MAXN          6005#define   maxnode       15#define   sigma_size    30#define   lson          l,m,rt<<1#define   rson          m+1,r,rt<<1|1#define   lrt           rt<<1#define   rrt           rt<<1|1#define   middle        int m=(r+l)>>1#define   LL            long long#define   ull           unsigned long long#define   mem(x,v)      memset(x,v,sizeof(x))#define   lowbit(x)     (x&-x)#define   pii           pair<int,int>#define   bits(a)       __builtin_popcount(a)#define   mk            make_pair#define   limit         10000//const int    prime = 999983;const int    INF   = 0x3f3f3f3f;const LL     INFF  = 0x3f3f;const double pi    = acos(-1.0);//const double inf   = 1e18;const double eps   = 1e-8;const LL    mod    = 1e9+7;const ull    mx    = 133333331;/*****************************************************/inline void RI(int &x) {    char c;    while((c=getchar())<'0' || c>'9');    x=c-'0';    while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; }/*****************************************************/struct Node{    int l,r,id;    bool operator < (const Node&e)const{        return r>e.r;    }}p[MAX*4];LL ans[MAX*4];int a[MAX];int pos[1000005];int pre[MAX];LL sum[MAX<<2];void pushup(int rt){    sum[rt]=sum[lrt]+sum[rrt];}void build(int l,int r,int rt){    sum[rt]=0;    if(l==r) return;    middle;    build(lson);    build(rson);    pushup(rt);}void update(int l,int r,int rt,int pos,int d){    if(l==r){        sum[rt]=d;        return;    }    middle;    if(pos<=m) update(lson,pos,d);    else update(rson,pos,d);    pushup(rt);}LL query(int l,int r,int rt,int L,int R){    if(L<=l&&r<=R) return sum[rt];    middle;    LL ans=0;    if(L<=m) ans+=query(lson,L,R);    if(R>m) ans+=query(rson,L,R);    return ans;}int main(){    int t;    cin>>t;    while(t--){        int n;        cin>>n;        mem(pre,-1);        for(int i=1;i<=n;i++){            scanf("%d",&a[i]);            pos[a[i]]=-1;        }        for(int i=1;i<=n;i++){            if(pos[a[i]]!=-1){                pre[i]=pos[a[i]];                pos[a[i]]=i;            }            else pos[a[i]]=i;        }        build(1,n,1);        int m;        cin>>m;        for(int i=0;i<m;i++){            int l,r;            scanf("%d%d",&l,&r);            p[i]=(Node){l,r,i};        }        sort(p,p+m);        for(int i=1;i<=n;i++){            if(pre[i]!=-1) update(1,n,1,pre[i],0);            update(1,n,1,i,a[i]);        }        int r=n;        for(int i=0;i<m;i++){            while(r>p[i].r){                if(pre[r]!=-1) update(1,n,1,pre[r],a[r]);                r--;            }            ans[p[i].id]=query(1,n,1,p[i].l,p[i].r);        }        for(int i=0;i<m;i++){            printf("%I64d\n",ans[i]);        }    }    return 0;}

hdu 4638
http://acm.hdu.edu.cn/showproblem.php?pid=4638
题意:求一个区间内,连续数字段的个数,比如一个区间内有1 2 3 4 5 ,就是一段,有1 2 4 ,就是两段。
这题也是莫队即可瞬秒,但是线段树的方法也是很难想,从莫队的维护的方法上考虑过来,如果一个数字出现,就把它当作独立的一段,就是个这个位置+1,然后如果和它相邻的数字出现,就应该-1,但是这个-1应该减哪里,如果我们枚举每个位置,然后看区间右端点是否小于这个位置来查询的话,如果相邻的两个数字都不在区间里,而这个位置-1的话,就会错误,所以应该是在相邻的数字的位置处-1.
考虑 1 2 3 ,扫到1,1位置+1,扫到2,2位置+1,1位置-1,然后查询是一段,扫到3, 3位置+1,2位置-1,查询[1,3]是1,查询[2,3]也是1,而此时不能查询[1,2],[1,2]这个区间应该是在扫到2的时候就查询了。
所以我们的方法是区间按照右端点排序,然后碰到一个点,就把他自己的位置+1,然后如果他的+1和-1的数字也在这个点的左边,那就在它们的位置上-1,然后碰到这个区间的时候就查询一下。


代码:

#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;#define   MAX           100005#define   MAXN          6005#define   maxnode       15#define   sigma_size    30#define   lson          l,m,rt<<1#define   rson          m+1,r,rt<<1|1#define   lrt           rt<<1#define   rrt           rt<<1|1#define   middle        int m=(r+l)>>1#define   LL            long long#define   ull           unsigned long long#define   mem(x,v)      memset(x,v,sizeof(x))#define   lowbit(x)     (x&-x)#define   pii           pair<int,int>#define   bits(a)       __builtin_popcount(a)#define   mk            make_pair#define   limit         10000//const int    prime = 999983;const int    INF   = 0x3f3f3f3f;const LL     INFF  = 0x3f3f;const double pi    = acos(-1.0);//const double inf   = 1e18;const double eps   = 1e-8;const LL    mod    = 1e9+7;const ull    mx    = 133333331;/*****************************************************/inline void RI(int &x) {    char c;    while((c=getchar())<'0' || c>'9');    x=c-'0';    while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; }/*****************************************************/int pos[MAX];int a[MAX];struct que{    int l,r,id;    bool operator < (const que&e)const{        return r<e.r;    }}p[MAX];int ans[MAX];int sum[MAX<<2];void pushup(int rt){    sum[rt]=sum[lrt]+sum[rrt];}void build(int l,int r,int rt){    if(l==r){        sum[rt]=0;        return;    }    middle;    build(lson);    build(rson);    pushup(rt);}void update(int l,int r,int rt,int pos,int d){    if(l==r){        sum[rt]+=d;        return;    }    middle;    if(pos<=m) update(lson,pos,d);    else update(rson,pos,d);    pushup(rt);}int query(int l,int r,int rt,int L,int R){    if(L<=l&&r<=R) return sum[rt];    middle;    int ans=0;    if(L<=m) ans+=query(lson,L,R);    if(R>m) ans+=query(rson,L,R);    return ans;}int main(){    int t;    cin>>t;    while(t--){        int n,m;        cin>>n>>m;        for(int i=1;i<=n;i++){            scanf("%d",&a[i]);            pos[a[i]]=i;        }        for(int i=0;i<m;i++){            int l,r;            scanf("%d%d",&l,&r);            p[i]=(que){l,r,i};        }        sort(p,p+m);        build(1,n,1);        int tot=0;        for(int i=1;i<=n;i++){            update(1,n,1,i,1);            if(pos[a[i]-1]&&pos[a[i]-1]<=i) update(1,n,1,pos[a[i]-1],-1);            if(pos[a[i]+1]&&pos[a[i]+1]<=i) update(1,n,1,pos[a[i]+1],-1);            while(tot<m&&p[tot].r==i){                ans[p[tot].id]=query(1,n,1,p[tot].l,p[tot].r);                tot++;            }        }        for(int i=0;i<m;i++) printf("%d\n",ans[i]);    }    return 0;}
0 0