树状数组和线段树

树状数组:
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;
}
posted @ 2023-11-25 20:17  Alric  阅读(4)  评论(0编辑  收藏  举报