加强树状数组luogu3368

本文介绍了一种利用差分技巧优化树状数组的方法,并通过一个具体的编程实例展示了如何使用差分树状数组来高效地解决区间更新问题。文章包含了完整的代码实现及解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

暴力树状数组30分,这该怎么办;

知识点回顾

差分数组中

开头结尾改变了值之后

求他的前缀,发现区间内所有数都改变

然后我们做差分树状数组


#include<cstdio>
using namespace std;
int n,m;
int c[501010];
int lowbit(int x){
    return x&-x; 
}
void update(int i,int x){
    while(i <= n){
        c[i] += x;
        i += lowbit(i);    
    }
}
int sum(int x)
{
    int sum = 0;
    while(x){
        sum += c[x];
        x -= lowbit(x);    
    } 
    return sum;
}
int main()
{
    scanf("%d%d",& n,& m);
    int x, y, z, k; 
    for(int i = 1;i <= n;++ i){
        scanf("%d",& x); 
        update(i,x),update(i+1,-x); 
    }
    while(m-- ){
        scanf("%d",& z);
        if(z == 2){
            scanf("%d",& x);
             printf("%d\n",sum(x));
        }else{
               scanf("%d%d%d",& x,& y,& k);
               update(x, k);update(y+1, -k);
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/dsrdsr/p/8987095.html

# P5629 【AFOI-19】区间与除法 ## 题目背景 SY 好不容易才解出QM给她的数学题,在恰午饭的时候,QM 向她的脑洞里塞了个幻想的泡泡……SY 戳开一看,又是长长的一串数字! SY 实在是不想思考了,她决定用小学的除法消灭她脑洞里的数字. ## 题目描述 定义 $op$ 操作意义为将当前数除以 $d$ 并向下取整. SY 现在有 $m$ 个“原数”,若一个数经过若干次 $op$ 操作(包括 $0$ 次)后能变为这个“原数”,那么这个数是可以被这个“原数”所消灭的。注意,“原数”是不会被消耗的. 现在 SY 想问你,对于一个区间 $[l,r]$,在消灭最多个数的前提下最少需要多少个“原数”? ## 输入格式 第一行 $4$ 个数,分别是 $n,m,d,q$,分别表示数列 $\{a\}$ 元素个数,SY 拥有的 “原数” 个数,$op$ 操作参数,询问个数。 第二行为 $\{a\}$ 数列,即需要被消灭的数列。 第三行为 $m$ 个“原数”。 接下来 $q$ 行,每行两个数 $l$ 和 $r$,表示询问区间为 $[l,r]$。 ## 输出格式 按照询问顺序,每一行输出一个整数表示答案. ## 输入输出样例 #1 ### 输入 #1 ``` 2 3 3 3 0 20 6 6 6 1 1 2 2 1 2 ``` ### 输出 #1 ``` 0 1 1 ``` ## 输入输出样例 #2 ### 输入 #2 ``` 6 3 3 3 6 5 10 15 19 7 2 5 10 1 6 1 4 4 6 ``` ### 输出 #2 ``` 3 3 2 ``` ## 说明/提示 #### 样例解释: **#样例1** : $20$ 经过一次 $op$ 操作(除以 $3$ 向下取整)可以变成 $6$,而 $0$ 不能经过若干次 $op$ 操作变成 $6$ 。 所以区间 $[1,1]$ 最多消灭 $0$ 个数,消灭最多数前提下最少需要 $0$ 个 "原数",区间 $[1,2],[2,2]$ 最多消灭 $1$ 个数,消灭最多数前提下最少需要 $1$ 个 "原数" 。 **#样例2** : $2$ 能消灭 $\{6,19,7\}$ , $5$ 能消灭 $\{5,15\}$ , $10$ 能消灭 $\{10\}$ , 所以区间 $[1,6],[1,4]$ 最少能用所有 "原数" 全部消灭,区间 $[4,6]$ 能用 $2,5$ 全部消灭。 #### 数据范围: 对于 $30\%$ 的数据:$n\le100,m\leq10, d=2, q\le 10$ 对于 $100\%$ 的数据:$n\le5\times 10^{5},m\leq60,2\leq d\leq10,q\le10^{6},0\le a_i,b_i\le 2^{63}$ ![](https://cdn.luogu.com.cn/upload/image_hosting/t7pn0p1n.png) 特殊性质:数据经过构造。 #include <bits/stdc++.h> #define ll long long using namespace std; const ll N=1e6; struct node{ ll l,r,sum; }tr[4*N+5]; struct xd{ ll l,r,f; }b[N+5]; ll n,m,d,q; ll a[N+5],ans[N+5]; ll pre[N+5],lst[N+5]; ll ys[N+5],dy[N+5]; map<ll,bool> mp; void updata(ll p){ tr[p].l=tr[2*p].l; tr[p].r=tr[2*p+1].r; tr[p].sum=tr[2*p].sum+tr[2*p+1].sum; return; } void build(ll p,ll l,ll r){ if(l==r){ tr[p].l=l; tr[p].r=r; return; } ll mid=(l+r)>>1; build(2*p,l,mid); build(2*p+1,mid+1,r); updata(p); return; } void change(ll p,ll x,ll y){ if(tr[p].l==x && tr[p].r==x){ tr[p].sum+=y; return; } if(x<=tr[2*p].r) change(2*p,x,y); else change(2*p+1,x,y); updata(p); return; } ll searchh(ll p,ll l,ll r){ if(r<l) return 0; ll s=0; if(tr[p].l==l && tr[p].r==r) return tr[p].sum; if(tr[2*p].r>=r) s+=searchh(2*p,l,r); else if(tr[2*p+1].l<=l) s+=searchh(2*p+1,l,r); else{ s+=searchh(2*p,l,tr[2*p].r); s+=searchh(2*p+1,tr[2*p+1].l,r); } return s; } bool cmp(xd l1,xd l2){ return l1.r<l2.r; } int main(){ memset(dy,-1,sizeof(dy)); scanf("%lld%lld%lld%lld",&n,&m,&d,&q); for(ll i=1;i<=n;i++) scanf("%lld",&a[i]); for(ll i=1;i<=m;i++) scanf("%lld",&ys[i]),mp[ys[i]]=1; for(ll i=1;i<=n;i++){ ll num=a[i],w=-1; if(mp[num]) w=num; while(num){ num/=d; if(mp[num]) w=num; } dy[i]=w; } // for(ll i=1;i<=n;i++) cout<<dy[i]<<" "; // return 0; for(ll i=1;i<=q;i++){ scanf("%lld%lld",&b[i].l,&b[i].r); b[i].f=i; // cout<<i<<endl; } for(ll i=1;i<=n;i++){ if(dy[i]==-1) continue; pre[i]=lst[dy[i]]; lst[dy[i]]=i; } build(1,1,n); sort(b+1,b+1+q,cmp); ll nxt=1; for(ll i=1;i<=q;i++){ while(nxt<=b[i].r){ if(dy[nxt]==-1){ nxt++; continue; } if(pre[nxt]) change(1,pre[nxt],-1); change(1,nxt,1); nxt++; } ans[b[i].f]=searchh(1,1,b[i].r)-searchh(1,1,b[i].l-1); } for(ll i=1;i<=q;i++) printf("%lld\n",ans[i]); return 0; } 时间限制3s,评测结果RE+TLE,找错误,并在不改变代码原本写法的情况下修正
08-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值