21天零基础入门ACM
21天零基础入门ACM之 第14天
线段树
线段树
线段树就是对一些满足区间可加性的数组的特性进行预处理。
线段树的基本实现
操作:
void pushup(int k){
tree[k]=tree[k<<1]+tree[k<<1|1];
}
建立:
void build(int k,int l,int r){
if(l==r) {
tree[k]=nums[l];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
更新:
void updata(int pos,int val,int k,int l,int r){
if(l==r) {
nums[k]+=val;
tree[k]+=val;
return;
}
int mid = (l+r)>>1;
if(pos<=mid) updata(pos,val,k<<1,l,mid);
else updata(pos,val,k<<1|1,mid+1,r);
pushup(k);
}
查询:
ll query(int L,int R,int k,int l,int r){
if(L<=l&&R>=r) return tree[k];
ll ans=0;
int mid = (l+r)>>1;
if(L<=mid) ans+=query(L,R,k<<1,l,mid);
if(R>mid) ans+=query(L,R,k<<1|1,mid+1,r);
return ans;
}
例题:
例题1:
https://ac.nowcoder.com/acm/problem/15164
代码:
#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define sc(x) scanf("%d",x)
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans *= a; b >>= 1; a *= a; } return ans; }
ll qpow(ll a, ll b, ll mod) { ll ans = 1; a%=mod; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
inline ll read() { ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; }
const int mod=1e9+7;
const int N=1e5+7;
int n,m;
ll nums[N],tree[N<<2];
void pushup(int k){
tree[k]=tree[k<<1]+tree[k<<1|1];
}
void build(int k,int l,int r){
if(l==r) {
tree[k]=nums[l];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
void updata(int pos,int val,int k,int l,int r){
if(l==r) {
nums[k]+=val;
tree[k]+=val;
return;
}
int mid = (l+r)>>1;
if(pos<=mid) updata(pos,val,k<<1,l,mid);
else updata(pos,val,k<<1|1,mid+1,r);
pushup(k);
}
ll query(int L,int R,int k,int l,int r){
if(L<=l&&R>=r) return tree[k];
ll ans=0;
int mid = (l+r)>>1;
if(L<=mid) ans+=query(L,R,k<<1,l,mid);
if(R>mid) ans+=query(L,R,k<<1|1,mid+1,r);
return ans;
}
ll x,y,z;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>nums[i];
build(1,1 ,n );
while(m--){
cin>>x>>y>>z;
if(x==1) updata(y,z,1,1,n);
else cout<<query(y,z,1,1,n)<<endl;
}
}
例题2:
https://ac.nowcoder.com/acm/problem/15163
代码:
#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define sc(x) scanf("%d",x)
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans *= a; b >>= 1; a *= a; } return ans; }
ll qpow(ll a, ll b, ll mod) { ll ans = 1; a%=mod; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
inline ll read() { ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; }
const int mod=1e9+7;
const int N=1e5+7;
int n,x;
int tree[N<<2];
void insert(int k,int l,int r,int x){
++tree[k];
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) insert(k<<1,l,mid,x);
else insert(k<<1|1,mid+1,r,x);
}
ll query(int L,int R,int k,int l,int r){
if(l>=L&&r<=R) return tree[k];
ll ans=0;
int mid=(l+r)>>1;
if(L<=mid) ans+=query(L,R,k<<1,l,mid);
if(mid<R) ans+=query(L,R, k<<1|1,mid+1, r);
return ans;
}
int main(){
n=read();
ll ans=0;
for(int i=0;i<n;i++){
x=read();
x++;
ans+=query(x+1,N,1,1,N);
insert(1,1,N,x);
}
cout<<ans<<endl;
}