Codeforces Round #179 (Div. 2) C Greg and Array 两个线段树

纯线段树的模板,只是要注意在计算加多少次的时候也当作线段树来做,注意longlong,为了保险我把所有int都改成了longlong
AC代码
#include<cstdio>
#include<iostream>
#include<cstring>
#define maxn 100010
#define ls l,m,nod<<1
#define rs m+1,r,nod<<1|1
using namespace std;
struct oper{
    long long l;
    long long r;
    long long val;
}op[maxn];
long long sum[maxn<<2],src[maxn];
long long flag[maxn<<2],n,q,m;
void pushup(long long nod){          //此题不用,可有可无
    sum[nod]=sum[nod<<1]+sum[nod<<1|1];
}
void pushdown(long long nod,long long m){
    if(flag[nod])
    {
        flag[nod<<1]+=flag[nod];
        flag[nod<<1|1]+=flag[nod];
        sum[nod<<1]+=(long long)(m-(m>>1))*flag[nod];
        sum[nod<<1|1]+=(long long)(m>>1)*flag[nod];
        flag[nod]=0;
    }
}
void build(long long l,long long r,long long nod)
{
    flag[nod]=0;
    if(l==r)
    {
        //cout<<nod;
        sum[nod] = 0;
        return;
    }
    long long m = (l+r)>>1;
    build(ls);
    build(rs);
    pushup(nod);
}
void update(long long ll,long long rr,long long val,long long l,long long r,long long nod)
{
    if(l>=ll&&r<=rr)
    {
        flag[nod]+=val;
        sum[nod]+=(long long)(r-l+1)*val;
        return;
    }
    pushdown(nod,r-l+1);
    long long m=(l+r)>>1;
    if(ll<=m)
        update(ll,rr,val,ls);
    if(rr>m)
        update(ll,rr,val,rs);
    pushup(nod);
}
long long query(long long ql,long long qr,long long l,long long r,long long nod){
    long long summ=0,ta=0,tb=0;
    if(l>=ql&&r<=qr)
        {summ+=sum[nod];
        return summ;}
    pushdown(nod,r-l+1);
    long long m=(l+r)>>1;
    if(ql<=m)
        ta=query(ql,qr,ls);
    if(qr>m)
        tb=query(ql,qr,rs);
    summ+=ta;
    summ+=tb;
    return summ;
}
int main(){
    memset(sum,0,sizeof(sum));
    scanf("%lld%lld%lld",&n,&m,&q);
    for(int i = 1; i <= n; i++)
        scanf("%lld",&src[i]);
    for(int i = 1; i <= m; i++)
        scanf("%lld%lld%lld",&op[i].l,&op[i].r,&op[i].val);
    build(1,m,1);
    long long a,b,v;

    /*for(int i = 0; i < 40; i++)
    cout<<sum[i]<<"  ";*/
    while(q--)
    {
        scanf("%lld%lld",&a,&b);
        update(a,b,1,1,m,1);
    }
    for(int i = 1; i <= m; i++)
        op[i].val*=query(i,i,1,m,1);
    memset(sum,0,sizeof(sum));
    build(1,n,1);
    for(int i = 1; i <= m; i++)
        update(op[i].l,op[i].r,op[i].val,1,n,1);
    printf("%lld",query(1,1,1,n,1) + src[1]);
    for(int i = 2; i <= n; i++)
        printf(" %lld",query(i,i,1,n,1) + src[i]);
    printf("\n");
}

后更:今天突然知道了一个非常屌的写法,用数组记录加减次数,加入数组为f,如果从i位置到j位置都加的话,就让f[i]++,f[j+1]--,最后再从1到n,f[i] += f[i-1],然后就能处理出来每次操作进行多少次了,同理,对上面值得修改也可以如此,附代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#define maxn 100010
using namespace std;
long long a[maxn],d[maxn],g[maxn];
int n,m,k,x,y,l[maxn],r[maxn],f[maxn];
int main(){
    cin>>m>>n>>k;
    for(int i = 1; i <= m; i++)
    scanf("%lld",a+i);
    for(int i = 1; i <= n; i++)
    scanf("%d%d%lld",l+i,r+i,d+i);


    for(int i = 1; i <= k; i++)
    scanf("%d%d",&x,&y),f[x]++,f[y+1]--;   //与下一步结合起来做,代表从x到y这个区间内所有的值都加了一
    for(int i = 1; i <= n; i++)
    f[i] += f[i-1];


    for(int i = 1; i <= n; i++)
    g[l[i]]+=d[i]*f[i],g[r[i] + 1]-=d[i]*f[i];   //同上
    for(int i = 1; i <= m; i++)
    g[i]+=g[i-1];



    for(int i = 1; i <= m; i++)
    printf("%lld ",g[i] + a[i]);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值