树状数组和线段树
树状数组:
1.将某一个数加上k
2.求出某区间每一个数的和
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,a[500000+10];
ll lowbit(ll x){return x&(-x);}
void update(ll x,ll k){
while(x<=n){
a[x]+=k;
x+=lowbit(x);
}
}
ll query(ll x){
ll ret=0;
while(x>0){
ret+=a[x];
x-=lowbit(x);
}
return ret;
}
int main(){
cin >> n >> m;
for(ll i=1;i<=n;i++){
ll temp;
cin >> temp;
a[i]+=temp;
if(i+lowbit(i)<=n)a[i+lowbit(i)]+=a[i];
}
for(ll i=1;i<=m;i++){
ll op,x,y;
cin >> op >> x >> y;
if(op==1)update(x,y);
else cout << query(y)-query(x-1) << endl;
}
return 0;
}
树状数组:
1.将某区间每一个数加上k
2.求出某一个数的值
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,a[500000+10],b[500000+10];
ll lowbit(ll x){return x&(-x);}
void update(ll x,ll k){
while(x<=n){
a[x]+=k;
x+=lowbit(x);
}
}
ll query(ll x){
ll ret=0;
while(x>0){
ret+=a[x];
x-=lowbit(x);
}
return ret;
}
int main(){
cin >> n >> m;
for(ll i=1;i<=n;i++)cin >> b[i];
for(ll i=1;i<=m;i++){
ll op,x,y,k;
cin >> op >> x;
if(op==1){
cin >> y >> k;
update(x,k);
update(y+1,-k);
}else{
cout << query(x)+b[x] << endl;
}
}
return 0;
}
树状数组:
1.将某区间每一个数加上k
2.求出某区间每一个数的和
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,a[2][500000+10],b[500000+10];
ll lowbit(ll x){
return x&(-x);
}
void update(ll type,ll x,ll k){
while(x<=n){
a[type][x]+=k;
x+=lowbit(x);
}
}
ll query(ll type,ll x){
ll ret=0;
while(x>0){
ret+=a[type][x];
x-=lowbit(x);
}
return ret;
}
int main(){
cin >> n >> m;
for(ll i=1;i<=n;i++)cin >> b[i],b[i]+=b[i-1];
for(ll i=1;i<=m;i++){
ll op,x,y,k,ans;
cin >> op >> x >> y;
if(op==1){
cin >> k;
update(0,x,k);
update(0,y+1,-k);
update(1,x,k*x);
update(1,y+1,-k*(y+1));
}else{
ans=(y+1)*query(0,y)-query(1,y)-x*query(0,x-1)+query(1,x-1)+b[y]-b[x-1];
cout << ans << endl;
}
}
return 0;
}
树状数组:
对于数列前奇数项求中位数
#include<bits/stdc++.h>
using namespace std;
typedef int ll;
vector<ll> dct;
ll n,a[100000+10],c[100000+10];
ll lowbit(ll x){return x&(-x);}
void update(ll x,ll k){
for(;x<=n;x+=lowbit(x))c[x]+=k;
}
ll query(ll x){
ll ret=0;
for(;x>0;x-=lowbit(x))ret+=c[x];
return ret;
}
int main(){
cin >> n;
for(ll i=1;i<=n;i++)cin >> a[i],dct.push_back(a[i]);
sort(dct.begin(),dct.end());
dct.erase(unique(dct.begin(),dct.end()),dct.end());
for(ll i=1;i<=n;i++)a[i]=lower_bound(dct.begin(),dct.end(),a[i])-dct.begin()+1;
for(ll i=1;i<=n;i++){
update(a[i],1);
if(i%2==1){
ll p=0,sum=0;
for(ll j=log(n)/log(2);j>=0;j--){
if(sum+c[p+(1<<j)]<(i+1)/2&&p+(1<<j)<=n){
sum+=c[p+(1<<j)];
p+=(1<<j);
}
}
cout << dct[p] << endl;
}
}
return 0;
}
树状数组:
1.将矩形区域内的所有数字加上k
2.求矩形区域内所有数字的和
#include<bits/stdc++.h>
using namespace std;
typedef int ll;
char ch;
ll n,m,a[4][2048+10][2048+10];
ll lowbit(ll x){return x&(-x);}
void update(ll t,ll x,ll y,ll k){
for(ll i=x;i<=n;i+=lowbit(i))
for(ll j=y;j<=m;j+=lowbit(j))
a[t][i][j]+=k;
}
ll query(ll t,ll x,ll y){
ll ret=0;
for(ll i=x;i>0;i-=lowbit(i))
for(ll j=y;j>0;j-=lowbit(j))
ret+=a[t][i][j];
return ret;
}
void change(ll x,ll y,ll k){
update(0,x,y,k);
update(1,x,y,k*x);
update(2,x,y,k*y);
update(3,x,y,k*x*y);
}
ll ask(ll x,ll y){
return (x+1)*(y+1)*query(0,x,y)-(y+1)*query(1,x,y)-(x+1)*query(2,x,y)+query(3,x,y);
}
int main(){
cin >> ch >> n >> m;
while(cin >> ch){
ll x1,y1,x2,y2,k;
if(ch=='L'){
cin >> x1 >> y1 >> x2 >> y2 >> k;
change(x1,y1,k);
change(x1,y2+1,-k);
change(x2+1,y1,-k);
change(x2+1,y2+1,k);
}else if(ch=='k'){
cin >> x1 >> y1 >> x2 >> y2;
cout << ask(x2,y2)-ask(x1-1,y2)-ask(x2,y1-1)+ask(x1-1,y1-1) << endl;
}
}
return 0;
}
线段树:
1.将某一个数加上k
2.求出某区间每一个数的和
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,a[500000+10],dat[500000*4+10],lazy[500000*4+10];
void down(ll p,ll l,ll r){
if(lazy[p]==0||l==r)return;
ll mid=(l+r)>>1;
lazy[p<<1]+=lazy[p];
lazy[(p<<1)|1]+=lazy[p];
dat[p<<1]+=(mid-l+1)*lazy[p];
dat[(p<<1)|1]+=(r-mid)*lazy[p];
lazy[p]=0;
}
void update(ll p,ll l,ll r,ll L,ll R,ll k){
if(L<=l&&r<=R){
dat[p]+=(r-l+1)*k;
lazy[p]+=k;
return;
}
down(p,l,r);
ll mid=(l+r)>>1;
if(L<=mid)update(p<<1,l,mid,L,R,k);
if(mid+1<=R)update((p<<1)|1,mid+1,r,L,R,k);
dat[p]=dat[p<<1]+dat[(p<<1)|1];
}
ll query(ll p,ll l,ll r,ll x){
ll ret=0;
if(l==r)return dat[p];
down(p,l,r);
ll mid=(l+r)>>1;
if(x<=mid)ret=query(p<<1,l,mid,x);
else ret=query((p<<1)|1,mid+1,r,x);
return ret;
}
int main(){
cin >> n >> m;
for(ll i=1;i<=n;i++)cin >> a[i];
while(m--){
ll op,l,r,k,x;
cin >> op;
if(op==1){
cin >> l >> r >> k;
update(1,1,n,l,r,k);
}else if(op==2){
cin >> x;
cout << query(1,1,n,x)+a[x] << endl;
}
}
return 0;
}
线段树:
1.将某区间每一个数加上k
2.求出某区间每一个数的和
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,a[100000+10],dat[100000*4+10],lazy[100000*4+10];
void down(ll p,ll l,ll r){
if(lazy[p]==0||l==r)return;
ll mid=(l+r)>>1;
lazy[p<<1]+=lazy[p];
dat[p<<1]+=(mid-l+1)*lazy[p];
lazy[(p<<1)|1]+=lazy[p];
dat[(p<<1)|1]+=(r-mid)*lazy[p];
lazy[p]=0;
}
void update(ll p,ll l,ll r,ll L,ll R,ll k){
if(L<=l&&r<=R){
dat[p]+=(r-l+1)*k;
lazy[p]+=k;
return;
}
down(p,l,r);
ll mid=(l+r)>>1;
if(L<=mid)update(p<<1,l,mid,L,R,k);
if(mid+1<=R)update((p<<1)|1,mid+1,r,L,R,k);
dat[p]=dat[p<<1]+dat[(p<<1)|1];
}
ll query(ll p,ll l,ll r,ll L,ll R){
if(L<=l&&r<=R){
return dat[p];
}
down(p,l,r);
ll ret=0,mid=(l+r)>>1;
if(L<=mid)ret+=query(p<<1,l,mid,L,R);
if(mid+1<=R)ret+=query((p<<1)|1,mid+1,r,L,R);
return ret;
}
int main(){
cin >> n >> m;
for(ll i=1;i<=n;i++)cin >> a[i],a[i]+=a[i-1];
while(m--){
ll op,l,r,k;
cin >> op >> l >> r;
if(op==1){
cin >> k;
update(1,1,n,l,r,k);
}else if(op==2){
cout << query(1,1,n,l,r)+a[r]-a[l-1] << endl;
}
}
return 0;
}
线段树:
1.将某区间每一个数乘上k
2.将某区间每一个数加上k
3.求出某区间每一个数的和
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
using namespace std;
typedef long long ll;
ll n,m,dat[100000*4+10],add[100000*4+10],mul[100000*4+10],mod;
void build(ll p,ll l,ll r){
mul[p]=1;
if(l==r){
cin >> dat[p];
return;
}
build(p<<1,l,mid);
build((p<<1)|1,mid+1,r);
dat[p]=(dat[p<<1]+dat[(p<<1)|1])%mod;
}
void down(ll p,ll l,ll r){
if(l==r)return;
if(add[p]==0&&mul[p]==1)return;
dat[p<<1]=(dat[p<<1]*mul[p]+(mid-l+1)*add[p])%mod;
dat[(p<<1)|1]=(dat[(p<<1)|1]*mul[p]+(r-mid)*add[p])%mod;
mul[p<<1]=mul[p<<1]*mul[p]%mod;
mul[(p<<1)|1]=mul[(p<<1)|1]*mul[p]%mod;
add[p<<1]=(add[p<<1]*mul[p]+add[p])%mod;
add[(p<<1)|1]=(add[(p<<1)|1]*mul[p]+add[p])%mod;
add[p]=0;
mul[p]=1;
}
void update_mul(ll p,ll l,ll r,ll L,ll R,ll k){
if(L<=l&&r<=R){
dat[p]=dat[p]*k%mod;
mul[p]=mul[p]*k%mod;
add[p]=add[p]*k%mod;
return;
}
down(p,l,r);
if(L<=mid)update_mul(p<<1,l,mid,L,R,k);
if(mid<R)update_mul((p<<1)|1,mid+1,r,L,R,k);
dat[p]=(dat[p<<1]+dat[(p<<1)|1])%mod;
}
void update_add(ll p,ll l,ll r,ll L,ll R,ll k){
if(L<=l&&r<=R){
dat[p]=(dat[p]+k*(r-l+1))%mod;
add[p]=(add[p]+k)%mod;
return;
}
down(p,l,r);
if(L<=mid)update_add(p<<1,l,mid,L,R,k);
if(mid<R)update_add((p<<1)|1,mid+1,r,L,R,k);
dat[p]=(dat[p<<1]+dat[(p<<1)|1])%mod;
}
ll query(ll p,ll l,ll r,ll L,ll R){
if(L<=l&&r<=R){
return dat[p];
}
down(p,l,r);
ll ret=0;
if(L<=mid)ret+=query(p<<1,l,mid,L,R);
if(mid<R)ret+=query((p<<1)|1,mid+1,r,L,R);
return ret%mod;
}
int main(){
cin >> n >> mod;
build(1,1,n);
cin >> m;
while(m--){
ll op,l,r,k;
cin >> op >> l >> r;
if(op==1){
cin >> k;
update_mul(1,1,n,l,r,k);
}else if(op==2){
cin >> k;
update_add(1,1,n,l,r,k);
}else if(op==3){
cout << query(1,1,n,l,r) << endl;
}
}
return 0;
}
线段树:
对于数列前奇数项求中位数
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
using namespace std;
typedef long long ll;
vector<ll> dct;
ll n,a[100000+10],dat[100000*4+10];
void update(ll p,ll l,ll r,ll x){
if(l==r){
dat[p]+=1;
return;
}
if(x<=mid)update(p<<1,l,mid,x);
else update((p<<1)|1,mid+1,r,x);
dat[p]=dat[p<<1]+dat[(p<<1)|1];
}
ll query(ll p,ll l,ll r,ll k){
if(l==r)return l;
ll ret;
if(k<=dat[p<<1])ret=query(p<<1,l,mid,k);
else ret=query((p<<1)|1,mid+1,r,k-dat[p<<1]);
return ret;
}
int main(){
cin >> n;
for(ll i=1;i<=n;i++)cin >> a[i],dct.push_back(a[i]);
sort(dct.begin(),dct.end());
dct.erase(unique(dct.begin(),dct.end()),dct.end());
for(ll i=1;i<=n;i++){
a[i]=lower_bound(dct.begin(),dct.end(),a[i])-dct.begin()+1;
}
for(ll i=1;i<=n;i++){
update(1,1,n,a[i]);
if(i%2){
cout << dct[query(1,1,n,(i+1)/2)-1] << endl;
}
}
return 0;
}
线段树合并:
进行m次操作,每次将一条树链上每个节点放1个1种颜色的物品。
求所有操作后,每个节点上的物品最多的是哪种颜色。
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
using namespace std;
typedef int ll;
vector<ll> dct;
vector<ll> G[100000+10];
ll n,m;
ll dep[100000+10],lg[100000+10],f[100000+10][20];
ll qsx[100000+10],qsy[100000+10],qst[100000+10];
ll dat[100000*80+10],type[100000*80+10];
ll lc[100000*80+10],rc[100000*80+10],tot;
ll ans[100000+10];
ll build(){
tot++;
dat[tot]=lc[tot]=rc[tot]=0;
return tot;
}
ll query(ll p,ll l,ll r,ll x){
if(p==0)return 0;
if(l==r){
return dat[p];
}
if(x<=mid)return query(lc[p],l,mid,x);
else return query(rc[p],mid+1,r,x);
}
void update(ll p,ll l,ll r,ll x,ll k){
if(l==r){
dat[p]+=k;
type[p]=x;
return;
}
if(x<=mid){
if(lc[p]==0)lc[p]=build();
update(lc[p],l,mid,x,k);
}else{
if(rc[p]==0)rc[p]=build();
update(rc[p],mid+1,r,x,k);
}
if(dat[lc[p]]>=dat[rc[p]]){
type[p]=type[lc[p]];
}else{
type[p]=type[rc[p]];
}
dat[p]=max(dat[lc[p]],dat[rc[p]]);
}
ll merge(ll p,ll q,ll l,ll r){
if(!p)return q;
if(!q)return p;
if(l==r){
dat[p]+=dat[q];
type[p]=l;
return p;
}
lc[p]=merge(lc[p],lc[q],l,mid);
rc[p]=merge(rc[p],rc[q],mid+1,r);
if(dat[lc[p]]>=dat[rc[p]]){
type[p]=type[lc[p]];
}else{
type[p]=type[rc[p]];
}
dat[p]=max(dat[lc[p]],dat[rc[p]]);
return p;
}
void dfs(ll u,ll fa){
for(ll i=0;i<G[u].size();i++){
ll v=G[u][i];
if(v==fa)continue;
dfs(v,u);
merge(u,v,1,m);
}
if(dat[u]==0)ans[u]=0;
else ans[u]=dct[type[u]-1];
}
void dfslca(ll u,ll fa){
f[u][0]=fa;
dep[u]=dep[fa]+1;
for(ll i=1;dep[u]-(1<<i)>=1;i++){
f[u][i]=f[f[u][i-1]][i-1];
}
for(ll i=0;i<G[u].size();i++){
ll v=G[u][i];
if(v==fa)continue;
dfslca(v,u);
}
}
ll lca(ll x,ll y){
if(dep[x]<dep[y])swap(x,y);
while(dep[x]>dep[y])x=f[x][lg[dep[x]-dep[y]]];
if(x==y)return x;
for(ll i=lg[dep[x]-1];i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin >> n >> m;
tot=n;
for(ll i=1;i<=n;i++)lg[i]=lg[i-1]+(1<<(lg[i-1]+1)==i);
for(ll i=1;i<=n-1;i++){
ll u,v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
dfslca(1,0);
for(ll i=1;i<=m;i++){
cin >> qsx[i] >> qsy[i] >> qst[i];
dct.push_back(qst[i]);
}
sort(dct.begin(),dct.end());
dct.erase(unique(dct.begin(),dct.end()),dct.end());
for(ll i=1;i<=m;i++){
ll lcaxy=lca(qsx[i],qsy[i]);
qst[i]=lower_bound(dct.begin(),dct.end(),qst[i])-dct.begin()+1;
update(qsx[i],1,m,qst[i],1);
update(qsy[i],1,m,qst[i],1);
update(lcaxy,1,m,qst[i],-1);
if(lcaxy!=1)update(f[lcaxy][0],1,m,qst[i],-1);
}
dfs(1,0);
for(ll i=1;i<=n;i++){
cout << ans[i] << endl;
}
return 0;
}
可持久化线段树:
维护一个数组,支持
1.在某个历史版本上修改某一个位置上的值
2.访问某个历史版本上的某一位置的值
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
using namespace std;
typedef int ll;
ll n,q;
ll root[1000000+10];
ll dat[1000000*20*2+10],lc[1000000*20*2+10],rc[1000000*20*2+10],tot;
ll build(ll l,ll r){
ll p=++tot;
if(l==r){
cin >> dat[p];
return p;
}
lc[p]=build(l,mid);
rc[p]=build(mid+1,r);
return p;
}
ll insert(ll now,ll l,ll r,ll x,ll k){
ll p=++tot;
lc[p]=lc[now],rc[p]=rc[now],dat[p]=dat[now];
if(l==r){
dat[p]=k;
return p;
}
if(x<=mid)lc[p]=insert(lc[now],l,mid,x,k);
else rc[p]=insert(rc[now],mid+1,r,x,k);
return p;
}
ll ask(ll now,ll l,ll r,ll x){
if(l==r)return dat[now];
if(x<=mid)return ask(lc[now],l,mid,x);
else return ask(rc[now],mid+1,r,x);
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin >> n >> q;
root[0]=build(1,n);
for(ll i=1;i<=q;i++){
ll v,op,loc,value;
cin >> v >> op >> loc;
if(op==1){
cin >> value;
root[i]=insert(root[v],1,n,loc,value);
}else{
cout << ask(root[v],1,n,loc) << endl;
root[i]=root[v];
}
}
return 0;
}
树状数组+可持久化线段树:
1.查询区间第k小的数
2.修改一个数
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
using namespace std;
typedef int ll;
ll lowbit(ll x){return x&(-x);}
vector<ll> dct;
ll n,qq,m;
ll a[100000+10];
ll root[100000+10];
ll dat[100000*20*20+10],lc[100000*20*20+10],rc[100000*20*20+10],tot;
char qsop[100000+10];
ll qsl[100000+10],qsr[100000+10],qsk[100000+10],qsx[100000+10],qsy[100000+10];
ll build(ll l,ll r){
ll p=++tot;
if(l==r)return tot;
lc[p]=build(l,mid);
rc[p]=build(mid+1,r);
return tot;
}
ll insert(ll now,ll l,ll r,ll x,ll k){
ll p=++tot;
dat[p]=dat[now],lc[p]=lc[now],rc[p]=rc[now];
if(l==r){
dat[p]+=k;
return p;
}
if(x<=mid)lc[p]=insert(lc[now],l,mid,x,k);
else rc[p]=insert(rc[now],mid+1,r,x,k);
dat[p]=dat[lc[p]]+dat[rc[p]];
return p;
}
void update(ll x,ll pos,ll k){
ll roott;
for(;x<=n;x+=lowbit(x)){
roott=insert(root[x],1,m,pos,k);
root[x]=roott;
}
}ll ask(vector<ll> p,vector<ll> q,ll l,ll r,ll k){
if(l==r)return l;
ll lcnt=0;
for(ll i=0;i<p.size();i++)lcnt+=dat[lc[p[i]]];
for(ll i=0;i<q.size();i++)lcnt-=dat[lc[q[i]]];
if(k<=lcnt){
for(ll i=0;i<p.size();i++)p[i]=lc[p[i]];
for(ll i=0;i<q.size();i++)q[i]=lc[q[i]];
return ask(p,q,l,mid,k);
}else{
for(ll i=0;i<p.size();i++)p[i]=rc[p[i]];
for(ll i=0;i<q.size();i++)q[i]=rc[q[i]];
return ask(p,q,mid+1,r,k-lcnt);
}
}
ll kth(ll l,ll r,ll k){
vector<ll> p,q;
for(ll i=r;i>0;i-=lowbit(i))p.push_back(root[i]);
for(ll i=l-1;i>0;i-=lowbit(i))q.push_back(root[i]);
return ask(p,q,1,m,k);
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin >> n >> qq;
for(ll i=1;i<=n;i++){
cin >> a[i];
dct.push_back(a[i]);
}
for(ll i=1;i<=qq;i++){
cin >> qsop[i];
if(qsop[i]=='Q'){
cin >> qsl[i] >> qsr[i] >> qsk[i];
}else if(qsop[i]=='C'){
cin >> qsx[i] >> qsy[i];
dct.push_back(qsy[i]);
}
}
sort(dct.begin(),dct.end());
dct.erase(unique(dct.begin(),dct.end()),dct.end());
m=dct.size();
root[0]=build(1,m);
for(ll i=1;i<=n;i++)root[i]=root[0];
for(ll i=1;i<=n;i++){
a[i]=lower_bound(dct.begin(),dct.end(),a[i])-dct.begin()+1;
update(i,a[i],1);
}
for(ll i=1;i<=qq;i++){
if(qsop[i]=='Q'){
cout << dct[kth(qsl[i],qsr[i],qsk[i])-1] << endl;
}else if(qsop[i]=='C'){
qsy[i]=lower_bound(dct.begin(),dct.end(),qsy[i])-dct.begin()+1;
update(qsx[i],a[qsx[i]],-1);
a[qsx[i]]=qsy[i];
update(qsx[i],a[qsx[i]],1);
}
}
return 0;
}