离线专题学习

原创 2016年06月01日 17:33:38

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;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

ARP专题学习指导

  • 2015年08月24日 17:04
  • 212KB
  • 下载

指针专题学习

  • 2007年06月01日 12:39
  • 264KB
  • 下载

iReport专题学习之字段、参数04

在iReport中有三种类a型的对象可以用来保存数据,它们分别是Fields、Parameters、...

专题学习网站JSP

  • 2015年04月15日 20:04
  • 29.59MB
  • 下载

PMP计算专题学习【技术文档】

  • 2016年11月08日 13:56
  • 6.13MB
  • 下载

iReport专题学习之报表元素03

在本章节中我们主要学习可以在报表中使用的对象以及他们的相关属性。

RabbitMQ (消息队列)专题学习05 routing(路由)

基于RabbitMQ消息队列的路由分发模式

程序专题学习网站

  • 2016年01月26日 12:01
  • 100KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:离线专题学习
举报原因:
原因补充:

(最多只允许输入30个字)