树状数组
树状数组
它能干的线段树都可(好像它最基本也就支持单点修改,区间求和——前缀和相减)。。。优点是码量very小
inline void update(int x,int v){
for(;x<=n;x+=x&(-x))
c[x]+=v;
}
inline int query(int x){
int res=0;
for(;x>0;x-=x&(-x))
res+=c[x];
return res;
}
区间修改单点查询就把原数组差分一下就可详见
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
inline LL read(){
LL x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int N=1000000;
LL n,m;
LL a,c[N];
inline void update(LL x,LL v){
for(;x<=N;x+=x&(-x))
c[x]+=v;
}
inline LL query(LL x){
LL res=0;
for(;x;x-=x&(-x))
res+=c[x];
return res;
}
int main(){
n=read();m=read();
LL i,now=0;
for(i=1;i<=n;i++){
a=read();
update(i,a-now);
now=a;
}
LL op;LL x,y,k;
for(i=1;i<=m;i++){
op=read();
if(op==1){
x=read();y=read();k=read();
update(x,k);
update(y+1,-k);
}else{
x=read();printf("%lld\n",query(x));
}
}
return 0;
}
树状数组求逆序对
非常神的题
本质和这个一样
离散化一下
按价值从小到大排序
排完序之后用权值树状数组维护
比当前的数大的有$query(n)-query(a[i]) $个,先统计答案,然后再把这个数插进去
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=1e6+10;
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
int n,a[N],b[N];
int c[N];
void upd(int x,int v){for(int i=x;i<=n;i+=i&(-i)) c[i]+=v;}
int query(int x){int res=0;for(int i=x;i;i-=i&(-i)) res+=c[i];return res;}
int main() {
n=read();
for(int i=1;i<=n;i++) b[i]=a[i]=read();
sort(b+1,b+1+n);
int len=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++)
a[i]=lower_bound(b+1,b+1+len,a[i])-b;
ll ans=0;
for(int i=1;i<=n;i++) {
ans+=query(n)-query(a[i]);
upd(a[i],1);
}
printf("%lld\n",ans);
return 0;
}
老C的任务
把询问拆分,按\(x\)轴排序,\(y\)轴维护树状数组 ,把区间询问转化为前缀和相减
注意!!!树状数组要往上加到非常大大大
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int N=2000005;
int n,m,len,tot,cnt;
struct point{
int x,y,p;
}a[N];
struct ques{
int x1,y1,x2,y2;
}q[N];
struct line{
int l,r,h,id;
}li[N];
ll c[N];
inline void upd(int x,ll v){for(;x<=4*N;x+=x&(-x))c[x]+=v;}
inline ll query(int x){ll res=0;for(;x>0;x-=x&(-x))res+=c[x];return res;}
ll b[N];
bool cmp1(point a,point b){return a.x<b.x;}
bool cmp2(line a,line b){return a.h<b.h;}
ll ans[N];
int main(){
n=read();m=read();
for(int i=1;i<=n;i++){
a[i].x=read();a[i].y=read();a[i].p=read();
b[++len]=a[i].x;b[++len]=a[i].y;
}
for(int i=1;i<=m;i++){
q[i].x1=read();q[i].y1=read();q[i].x2=read();q[i].y2=read();
b[++len]=q[i].x1-1;b[++len]=q[i].y1-1;b[++len]=q[i].x2;b[++len]=q[i].y2;
}
sort(b+1,b+len+1);
tot=unique(b+1,b+1+len)-b-1;
for(int i=1;i<=n;i++){
a[i].x=lower_bound(b+1,b+1+len,a[i].x)-b;
a[i].y=lower_bound(b+1,b+1+len,a[i].y)-b;
}
for(int i=1;i<=m;i++){
q[i].x1=lower_bound(b+1,b+1+len,q[i].x1-1)-b;
q[i].y1=lower_bound(b+1,b+1+len,q[i].y1-1)-b;
q[i].x2=lower_bound(b+1,b+1+len,q[i].x2)-b;
q[i].y2=lower_bound(b+1,b+1+len,q[i].y2)-b;
li[i*2-1].h=q[i].x1;li[i*2-1].l=q[i].y1;li[i*2-1].r=q[i].y2;li[i*2-1].id=i;
li[i*2].h=q[i].x2;li[i*2].l=q[i].y1;li[i*2].r=q[i].y2;li[i*2].id=i;
}
sort(a+1,a+1+n,cmp1);
sort(li+1,li+1+2*m,cmp2);
int now=1;
for(int i=1;i<=2*m;i++){
while(a[now].x<=li[i].h&&now<=n){
upd(a[now].y,a[now].p); now++;
}
if(!ans[li[i].id]) ans[li[i].id]=query(li[i].r)-query(li[i].l);
else ans[li[i].id]=query(li[i].r)-query(li[i].l)-ans[li[i].id];
}
for(int i=1;i<=m;i++)
printf("%lld\n",ans[i]);
return 0;
}
Count 二维树状数组
就是多了层for
然后数颜色加一维状态 \([c]\)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int N=305;
int n,m,q;
int a[N][N];
int t[105][N][N];
void upd(int x,int y,int c,int v) {
for(int i=x;i<=n;i+=i&(-i))
for(int j=y;j<=m;j+=j&(-j))
t[c][i][j]+=v;
}
int query(int x,int y,int c) {
int res=0;
for(int i=x;i;i-=i&(-i))
for(int j=y;j;j-=j&(-j))
res+=t[c][i][j];
return res;
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) {
a[i][j]=read();
upd(i,j,a[i][j],1);
}
q=read();
int op,x1,x2,y1,y2,c;
for(int i=1;i<=q;i++){
op=read();
if(op==1){
x1=read();y1=read();c=read();
upd(x1,y1,a[x1][y1],-1);
a[x1][y1]=c;
upd(x1,y1,a[x1][y1],1);
}
else{
x1=read();x2=read();y1=read();y2=read();c=read();
printf("%d\n",query(x2,y2,c)+query(x1-1,y1-1,c)-query(x1-1,y2,c)-query(x2,y1-1,c));
}
}
return 0;
}
梦原
如果新的点比并上去的点苹果少,那么每次往上并上一个新的点,所产生的代价是0
如果新的点比并上去的点苹果多,那你就需要多花 多出来的苹果数 那么多,
那么对于新加的点\(i\),所产生的期望代价就是看\([i - k,i - 1]\)这里面的点哪些点比新点的\(val\)少,答案加上差值,然后除\(k\)
这可以用离散化的权值树状数组维护
具体代码中的\(a[i]\)是离散后的排名,\(c[a[i]]\)就是原始值
我们要维护区间 \([i-k,i-1]\)中 \(sum_a[i]\)及 其个数\(siz\),产生的代价即为\(a[now]*siz-sum_a[i]\);
#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=2005000;
const int P=998244353;
inline int read() {
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
#define MP make_pair
typedef long long LL;
int n,m,k;
int a[N],c[N];
LL inv[N];
inline void Max(int &x,int y){if(x<y)x=y;}
inline void Min(int &x,int y){if(x>y)x=y;}
inline void plu(int &x,int y){x+=y;x>=P&&(x-=P);}
int ct[N],cd[N];//权值树状数组——个数/和
inline void upd(int x,int v,int vv) {
for(;x<=m;x+=x&(-x)) plu(cd[x],v),ct[x]+=vv;
}
inline pair<int,int> query(int x) {
int sum=0,siz=0;
for(;x;x-=x&(-x)) plu(sum,cd[x]),siz+=ct[x];
return MP(sum,siz);
}
int main() {
n=read();k=read();
for(int i=1;i<=n;i++) c[i]=a[i]=read();
sort(c+1,c+1+n);m=unique(c+1,c+1+n)-c-1;
LL ans=a[1];
a[1]=lower_bound(c+1,c+1+m,a[1])-c;
upd(a[1],c[a[1]],1);
inv[0]=inv[1]=1;
for(int i=2;i<=k;i++)
inv[i]=(P-P/i)*inv[P%i]%P;
for(int i=2;i<=n;i++) {
if(i-k-1>=1) upd(a[i-k-1],P-c[a[i-k-1]],-1);
a[i]=lower_bound(c+1,c+1+m,a[i])-c;
pair<int,int> s=query(a[i]);
ans=(ans+inv[min(k,i-1)]*(1ll*c[a[i]]*s.second%P-s.first+P)%P)%P;
upd(a[i],c[a[i]],1);
}
printf("%lld\n",ans);
return 0;
}