CCF(除法):线段树区间修改(50分)+线段树点修改(100分)+线段树(100分)

除法

201709-5

  • 这道题有很多种方法来做,最常用的就是线段树和树状数组。
  • 如果使用线段树来做,就会想到区间修改的update函数。但是这里可能会涉及到v是1或者a[j]是0的情况,所以用这种方法会超时,最多50分。
  • 可以修改一下代码,使用点修改来做这道题。在main函数里面增加一个循环,用来判断。
  • 当然,还有一种方法就是树状数组,这种方法和上面这种方法运行时间相差无几,但是代码量大大减少。
  • 需要注意的是,如果v是long long型,最好不要用scanf %lld的方式读入,否则超时。

使用线段树代码:

//线段树求解
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=100005;
int n,m;
int a[maxn];
long long sum[maxn<<2];
void pushup(int id,int l,int r){
    int lc=id<<1;
    int rc=id<<1|1;
    sum[id]=sum[lc]+sum[rc];
}
void build(int id,int l,int r){
    if(l==r){
        sum[id]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    int lc=id<<1;
    int rc=id<<1|1;
    build(lc,l,mid);
    build(rc,mid+1,r);
    pushup(id,l,r);
}
//---------------------------区间修改
// void update(int id,int l,int r,int p,int q,int v){
//     if(l==r){
//         if(sum[id]>=v&&sum[id]%v==0)
//             sum[id]/=v;
//         return;
//     }
//     int mid=(l+r)>>1;
//     if(p<=mid){
//         update(id<<1,l,mid,p,q,v);
//     }
//     if(q>mid){
//         update(id<<1|1,mid+1,r,p,q,v);
//     }
//     pushup(id,l,r);
// }
//-------------------------------点修改
void update(int id,int l,int r,int p){
    if(l==r){
        sum[id]=a[p];
        return;
    }
    int mid=(l+r)>>1;
    if(p<=mid){
        update(id<<1,l,mid,p);
    }
    if(p>mid){
        update(id<<1|1,mid+1,r,p);
    }
    pushup(id,l,r);
}
long long query(int id,int l,int r,int p,int q){
    long long sums=0;
    if(p<=l&&q>=r){
        return sum[id];
    }
    int mid=(l+r)>>1;
    if(p<=mid){
        sums+=query(id<<1,l,mid,p,q);
    }
    if(q>mid){
        sums+=query(id<<1|1,mid+1,r,p,q);
    }
    return sums;
}
int main(){
    // ios::sync_with_stdio(false);
    // cin.tie(0);
    scanf("%d%d",&n,&m);
    //cin>>n>>m;
    for(int i=1;i<=n;i++){
        //cin>>a[i];
        scanf("%d",&a[i]);
    }
    build(1,1,n);
    for(int i=0;i<m;i++){
        int opt,p,q;
        scanf("%d%d%d",&opt,&p,&q);
        //cin>>opt>>p>>q;
        if(opt==1){//update
            int v;
            scanf("%d",&v);
            //cout<<v<<endl;
            //cin>>v;
            //-------------------------------区间修改
            // if(v==1)
            //     continue;
            // update(1,1,n,p,q,v);
            if(v==1)
                continue;
            //     //--------------------------点修改
            for(int j=p;j<=q;j++){
                if(a[j]>=v&&a[j]%v==0){
                    a[j]/=v;
                    update(1,1,n,j);
                }
            }
        }else{
            cout<<query(1,1,n,p,q)<<endl;
        }
    }
    //system("pause");
    return 0;
}

使用树状数组代码:

//树状数组求解
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=100005;
int n,m;
int a[maxn];
long long c[maxn];
int lowbit(int x){
    return x&(-x);
}
long long sum(int x){
    long long ret=0;
    while(x>0){
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}
void add(int x,int v){
    while(x<=n){
        c[x]+=v;
        x+=lowbit(x);
    }
}
int main(){
    // ios::sync_with_stdio(false);
    // cin.tie(0);
    //cin>>n>>m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        //cin>>a[i];
        scanf("%d",&a[i]);
        add(i,a[i]);
    }
    for(int i=0;i<m;i++){
        int opt;
        //cin>>opt;
        scanf("%d",&opt);
        if(opt==1){
            int p,q;int v;
            //cin>>p>>q>>v;
            scanf("%d%d%d",&p,&q,&v);//这里不能用%lld来读取long long 型,
            if(v==1)
                continue;
            for(int j=p;j<=q;j++){
                if(a[j]>=v&&a[j]%v==0){
                    add(j,a[j]/v-a[j]);
                    a[j]/=v;
                }
            }
        }else{
            int p,q;
            //cin>>p>>q;
            scanf("%d%d",&p,&q);
            cout<<sum(q)-sum(p-1)<<endl;
        }
    }
    //system("pause");
    return 0;
}

原文地址:https://www.cnblogs.com/GarrettWale/p/11456868.html

时间: 2024-11-08 00:34:13

CCF(除法):线段树区间修改(50分)+线段树点修改(100分)+线段树(100分)的相关文章

【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并

题目描述 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. 输入 The first line contains integer n (1 ≤ n ≤ 105), showing how many numbers the sequence has. The next line contains n integers a1, a2, ..., an (|ai| ≤ 500). The third line contain

CF 46 D Parking Lot(线段树区间合并)

Description Nowadays it is becoming increasingly difficult to park a car in cities successfully. Let's imagine a segment of a street as long as L meters along which a parking lot is located. Drivers should park their cars strictly parallel to the pav

hdu 3308(线段树区间合并)

LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6069    Accepted Submission(s): 2635 Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index

线段树区间修改模板

本来打算把大白书第三章一口气攻下来的,但是这个线段树也是卡了好久. 不敢过题太快,怕自己走马观花到头来结果什么都不会. 可也不能再拖了,在做题中也许有更多的体会. 模板一:1 L R v 表示区间[L, R]所有元素都加上v2 L R   表示查询区间[L, R]的sum, min, maxsumv[o]的定义为:如果只执行节点o及其子孙节点的中的add操作,节点o对应区间中所有数之和 1 //线段树区间修改 2 //1 L R v 表示区间[L, R]所有元素都加上v 3 //2 L R 表示

hihoCoder #1078 : 线段树的区间修改(线段树区间更新板子题)

#1078 : 线段树的区间修改 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 对于小Ho表现出的对线段树的理解,小Hi表示挺满意的,但是满意就够了么?于是小Hi将问题改了改,又出给了小Ho: 假设货架上从左到右摆放了N种商品,并且依次标号为1到N,其中标号为i的商品的价格为Pi.小Hi的每次操作分为两种可能,第一种是修改价格——小Hi给出一段区间[L, R]和一个新的价格NewP,所有标号在这段区间中的商品的价格都变成NewP.第二种操作是询问——小Hi给出一段

POJ 3468 A Simple Problem with Integers(线段树区间修改及查询)

Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval. In

杭电 1698 Just a Hook(线段树区间修改)

http://acm.hdu.edu.cn/showproblem.php?pid=1698 Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 17322    Accepted Submission(s): 8640 Problem Description In the game of DotA, Pudge's

【模板】线段树区间修改

区间修改: 区间修改过程类似于区间询问,例如将[ul, ur]内的所有元素都加上v,则进行如下操作: 当当前区间被区间[ul, ur]所包含时, 当前的节点值加上区间长度(r - l  + 1)乘以v 对当前节点的lazy-tag加上v,修改结束 否则,将当前节点的lazy-tag下传,分别修改左孩子和右孩子(一定条件下),然后更新此节点的值 lazy-tag下传: 如果当前节点没有lazy-tag,直接return 否则:1. 将左孩子右孩子分别加上lazy-tag * 区间长度的值  2.

hdu1698 Just a Hook(线段树+区间修改+区间查询+模板)

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 54923    Accepted Submission(s): 25566 Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of