文章目录
博客推荐
1.https://blog.csdn.net/flushhip/article/details/79165701
2.https://www.luogu.org/blog/Chanis/super-BIT
3.https://www.bestsort.cn/2019/04/26/195
4.https://www.cnblogs.com/aininot260/p/9336527.html
模板
一维树状数组
单点修改,区间查询
/************************
User:Mandy.H.Y
Language:c++
Problem:loj130 Binary Index Tree 1
Algorithm:Binary Index Tree
Date:2019.7.10
Scores:100
************************/
//单点修改,区间查询
//c[i]表示从第i个元素向前数lowbit(i)个元素,这一段的和
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int n,q;
long long sum[maxn];
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("130.in","r",stdin);
freopen("130.out","w",stdout);
}
int lowbit(int x){
return x & (-x);
}
void modify(int pos,int val){//i的父亲节点是i+lowbit(i)
for(int i=pos;i<=n;i+=lowbit(i)) sum[i]+=(long long)val;
}
void readdata(){
read(n);read(q);
for(int i=1;i<=n;++i){
int x;read(x);
modify(i,x);
}
}
long long query(int l,int r){
long long suml=0,sumr=0;
for(int i=r;i;i-=lowbit(i)) sumr+=(long long)sum[i];
for(int i=l-1;i;i-=lowbit(i)) suml+=(long long)sum[i];//注意long long
return sumr-suml;
}
void work(){
while(q--){
int opt;
read(opt);
if(opt==1){
int pos,val;read(pos);read(val);
modify(pos,val);
}else{
int l,r;
read(l);read(r);
put(query(l,r));putchar('\n');
}
}
}
int main(){
// file();
readdata();
work();
return 0;
}
区间修改,单点查询
/********************
User:Mandy.H.Y
Language:c++
Problem:loj131 Binary Index Tree 2
Algorithm:Binary Index Tree 2
Date:2019.7.10
Scores:
********************/
//区间修改,单点查询
//差分
//delta[i]=a[i]-a[i-1](a为原数组)
//把delta[i]整合为树状数组
//则delta[i]表示从第i个元素向前数lowbit(i)个元素,这一段的和
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int n,q;
long long delta[maxn];
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("131.in","r",stdin);
freopen("131.out","w",stdout);
}
int lowbit(int x){
return x & (-x);
}
void modify(int l,int r,int val){
for(int i=r+1;i<=n;i+=lowbit(i)) delta[i]-=(long long)val;
for(int i=l;i<=n;i+=lowbit(i)) delta[i]+=(long long)val;
}
long long query(int pos){
long long sum=0;
for(int i=pos;i;i-=lowbit(i)) sum+=delta[i];
return sum;
}
void readdata(){
read(n);read(q);
int x;
for(int i=1;i<=n;++i){
read(x);
modify(i,i,x);//这里直接加值,相当于把[i,i]这个区间所有值加上x
}
}
void work(){
while(q--){
int opt;read(opt);
if(opt==1){
int l,r,x;read(l);read(r);read(x);
modify(l,r,x);
}else{
int pos;read(pos);
put(query(pos));putchar('\n');
}
}
}
int main(){
// file();
readdata();
work();
return 0;
}
//第二种方法
/*
User:Mandy.H.Y
Language:c++
Problem:
*/
/*
//c[i]表示从第i个元素向前数lowbit(i)个元素,这一段的和
#include<bits/stdc++.h>
#define Max(x,y) (x)>(y)?(x):(y)
#define Min(x,y) (x)<(y)?(x):(y)
#define mem(A) memset((A),0,sizeof(A))
using namespace std;
const int maxn=1e6+5;
int n,q;
long long sum[maxn];
template<typename T>inline void read(T &x)
{
x=0;char c=getchar();bool f=0;
while(c<'0'||c>'9') {f|=(c=='-');c=getchar();}
while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
if(f) x=-x;
}
template<typename T>void putch(const T x)
{
if(x>9) putch(x/10);
putchar((x%10)|48);
}
template<typename T>inline void put(const T x)
{
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void docu()
{
freopen("pasture.txt","r",stdin);
}
int lowbit(int x)
{
return x&(-x);
}
void modify(int k,int x)
{
for(int i=k;i<=n;i+=lowbit(i))
{
sum[i]+=(long long)x;
}
}
void query(int r)
{
long long sum1=0;
for(int i=r;i>0;i-=lowbit(i)) sum1+=sum[i];
printf("%lld\n",sum1);
}
void readdata()
{
read(n);read(q);
int pre=0;
for(int i=1;i<=n;++i)
{
int x;
read(x);
modify(i,x-pre);
pre=x;
}
}
void work()
{
for(int i=1;i<=q;++i)
{
int judge,j,x,k;
read(judge);
if(judge==1)
{
read(j); read(k); read(x);
modify(j,x);
modify(k+1,-x);
}
else
{
read(x);
query(x);
}
}
}
int main()
{
// docu();
readdata();
work();
return 0;
}
*/
区间修改,区间查询
/*************************
User:Mandy.H.Y
Language:c++
Problem:loj132 Binary Index Tree 3
Algorithm:
Date:2019.7.10
Scores:
*************************/
//区间修改,区间查询
//设d[i]=a[i]-a[i-1];
//则sum[i]=d[j]*(i-j+1)(j= 1 to i)
//sum[i]=d[j]*(i+1)-d[j]*j (j= 1 to i)
//把d整合为树状数组,修改时向父节点推
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int n,q;
long long sum[maxn],delta1[maxn],delta2[maxn];
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("132.in","r",stdin);
freopen("132.out","w",stdout);
}
void readdata(){
read(n);read(q);
for(int i=1;i<=n;++i){
int x;read(x);
sum[i]=sum[i-1]+x;//事先求出sum,delta 中只存改变量
}
}
int lowbit(int x){
return x&(-x);
}
void add(int pos,int val){
long long mval=(long long)val*(long long)pos;
for(int i=pos;i<=n;i+=lowbit(i)){
delta1[i]+=val;
delta2[i]+=mval;
}//向上
}
long long query(int pos){
long long sum1=0,sum2=0;
for(int i=pos;i;i-=lowbit(i)){
sum1+=delta1[i];
sum2+=delta2[i];
}
return sum[pos]+sum1*(pos+1)-sum2;
}
void work(){
while(q--){
int opt,l,r,x;read(opt);
if(opt==1){
read(l);read(r);read(x);
add(l,x);add(r+1,-x);
}else{
read(l);read(r);
put(query(r)-query(l-1));
putchar('\n');
}
}
}
int main(){
// file();
readdata();
work();
return 0;
}
二维树状数组
单点修改,区间查询
/************************
User:Mandy.H.Y
Language:c++
Problem:
Algorithm:
Date:
Score:
************************/
//单点修改,区间查询
#include<bits/stdc++.h>
using namespace std;
const int maxn = (1 << 12) + 5;
int n,m;
long long a[maxn][maxn];
template<class T>inline void read(T &x){
x = 0;bool flag = 0;char ch = getchar();
while( ! isdigit(ch)) flag |= ch == '-',ch = getchar();
while( isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
if(flag)x = -x;
}
template<class T>void putch(const T x){
if(x > 9) putch(x / 10);
putchar(x % 10 | 48);
}
template<class T>void put(const T x){
if(x < 0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("1.in","r",stdin);
freopen("133.out","w",stdout);
}
void readdata(){
read(n);read(m);
}
int lowbit(int x){
return x & (-x);
}
void modify(int x,int y,long long val){
for(int i = x;i <= n;i += lowbit(i))
a[i][j] += val;
}
long long query(int x,int y){
long long sum=0;
for(int i = x;i;i -= lowbit(i))
for(int j = y;j;j -= lowbit(j))
sum += a[i][j];
return sum;
}
void work(){
int opt,a,b,c,d;
long long delta;
while(~scanf("%d",&opt)){
if(opt == 1){
read(a);read(b);read(delta);
modify(a,b,delta);
}else if(opt == 2){
read(a);read(b);read(c);read(d);
long long ans = query(c,d) - query(c,b - 1)
- query(a - 1,d) + query(a - 1,b - 1);
put(ans);putchar('\n');
}
}
}
int main(){
file();
readdata();
work();
return 0;
}
区间修改,单点查询 && 区间修改,区间查询
代码引自: 数据结构:二维树状数组、三维树状数组 BY静听风吟。
https://www.cnblogs.com/aininot260/p/9336527.html
//单点修改,区间查询
#include<iostream>
using namespace std;
const int maxn=1005;
const int maxm=1005;
int n,m;
int q;
int a[maxn][maxm];
int c[maxn][maxm];
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int y,int z)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=m;j+=lowbit(j))
c[i][j]+=z;
}
int sum(int x,int y)
{
int ret=0;
for(int i=x;i>=1;i-=lowbit(i))
for(int j=y;j>=1;j-=lowbit(j))
ret+=c[i][j];
return ret;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
update(i,j,a[i][j]);
}
cin>>q;
while(q--)
{
int x;
cin>>x;
if(x==1)
{
int y,z,w;
cin>>y>>z>>w;
update(y,z,w);
}
if(x==2)
{
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
cout<<sum(x2,y2)-sum(x1-1,y2)-sum(x2,y1-1)+sum(x1-1,y1-1)<<endl;
}
}
return 0;
}
//区间修改,单点查询
#include<iostream>
using namespace std;
const int maxn=1005;
const int maxm=1005;
int n,m;
int q;
int a[maxn][maxm];
int c[maxn][maxm];
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int y,int z)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=m;j+=lowbit(j))
c[i][j]+=z;
}
int sum(int x,int y)
{
int ret=0;
for(int i=x;i>=1;i-=lowbit(i))
for(int j=y;j>=1;j-=lowbit(j))
ret+=c[i][j];
return ret;
}
int main()
{
cin>>n>>m;
cin>>q;
while(q--)
{
int x;
cin>>x;
if(x==1)
{
int x1,y1,x2,y2,w;
cin>>x1>>y1>>x2>>y2>>w;
update(x1,y1,w);
update(x2+1,y2+1,w);
update(x2+1,y1,-w);
update(x1,y2+1,-w);
}
if(x==2)
{
int x,y;
cin>>x>>y;
cout<<sum(x,y)<<endl;
}
}
return 0;
}
//区间修改,区间查询
//这样快一点
#include<bits/stdc++.h>
using namespace std;
const int maxn = (1 << 11) + 5;
int n,m;
int a1[maxn][maxn];
int a2[maxn][maxn];
int a3[maxn][maxn];
int a4[maxn][maxn];//开long long 会爆空间
template<class T>inline void read(T &x){
x = 0;bool flag = 0;char ch = getchar();
while( ! isdigit(ch)) flag |= ch == '-',ch = getchar();
while( isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
if(flag)x = -x;
}
template<class T>void putch(const T x){
if(x > 9) putch(x / 10);
putchar(x % 10 | 48);
}
template<class T>void put(const T x){
if(x < 0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("4514.in","r",stdin);
freopen("4514.out","w",stdout);
}
void readdata(){
read(n);read(m);
}
int lowbit(int x){
return x & (-x);
}
void modify(int x,int y,int val){
for(int i = x;i <= n;i += lowbit(i))
for(int j = y;j <= m;j += lowbit(j)){
a1[i][j] += val;
a2[i][j] += val * x;
a3[i][j] += val * y;
a4[i][j] += val * x * y;
}
}
int query(int x,int y){
int sum1 = 0,sum2 = 0,sum3 = 0,sum4 = 0;
for(int i = x;i;i -= lowbit(i))
for(int j = y;j;j -= lowbit(j)){
sum1 += a1[i][j];
sum2 += a2[i][j];
sum3 += a3[i][j];
sum4 += a4[i][j];//一起算,否则会爆时间
}
return sum1 * (x + 1) * (y + 1) -
sum2 * (y + 1) -
sum3 * (x + 1) +
sum4;
}
void work(){
char opt;
int a,b,c,d;
int delta;
while(~scanf("%c",&opt)){
if(opt == 'L'){
read(a);read(b);read(c);read(d);read(delta);
modify(a,b,delta);
modify(c + 1,d + 1,delta);
modify(a,d + 1,-delta);
modify(c + 1,b,-delta);
}else if(opt == 'k'){
read(a);read(b);read(c);read(d);
int ans1 = query(c,d);
int ans2 = query(c,b - 1);
int ans3 = query(a - 1,d);
int ans4 = query(a - 1,b - 1);
put(ans1 - ans2 - ans3 + ans4);putchar('\n');
}
}
}
int main(){
// file();
readdata();
work();
return 0;
}
//这样也行
#include<iostream>
using namespace std;
const int maxn=1005;
const int maxm=1005;
int n,m;
int q;
int a[maxn][maxm];
int c1[maxn][maxm];
int c2[maxn][maxm];
int c3[maxn][maxm];
int c4[maxn][maxm];
int lowbit(int x)
{
return x&(-x);
}
void update(int c[][maxm],int x,int y,int z)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=m;j+=lowbit(j))
c[i][j]+=z;
}
int sum(int c[][maxm],int x,int y)
{
int ret=0;
for(int i=x;i>=1;i-=lowbit(i))
for(int j=y;j>=1;j-=lowbit(j))
ret+=c[i][j];
return ret;
}
int get(int x,int y)
{
return sum(c1,x,y)*(x+1)*(y+1)-sum(c2,x,y)*(y+1)-(x+1)*sum(c3,x,y)+sum(c4,x,y);
}
int main()
{
cin>>n>>m;
cin>>q;
while(q--)
{
int x;
cin>>x;
if(x==1)
{
int x1,y1,x2,y2,w;
cin>>x1>>y1>>x2>>y2>>w;
update(c1,x1,y1,w),update(c1,x1,y2+1,-w);
update(c1,x2+1,y1,-w),update(c1,x2+1,y2+1,w);
update(c2,x1,y1,w*x1),update(c2,x2+1,y1,-w*(x2+1));
update(c2,x1,y2+1,-w*x1),update(c2,x2+1,y2+1,w*(x2+1));
update(c3,x1,y1,w*y1),update(c3,x2+1,y1,-w*y1);
update(c3,x1,y2+1,-w*(y2+1)),update(c3,x2+1,y2+1,w*(y2+1));
update(c4,x1,y1,w*x1*y1),update(c4,x2+1,y1,-w*(x2+1)*y1);
update(c4,x1,y2+1,-w*x1*(y2+1)),update(c4,x2+1,y2+1,w*(x2+1)*(y2+1));
}
if(x==2)
{
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
cout<<get(x2,y2)-get(x2,y1-1)-get(x1-1,y2)+get(x1-1,y1-1)<<endl;
}
}
return 0;
}
//三维树状数组修改区间查询点
#include<iostream>
using namespace std;
const int maxn=105;
const int maxm=105;
const int maxl=105;
int n,m,l;
int q;
int a[maxn][maxm][maxl];
int c[maxn][maxm][maxl];
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int y,int z,int w)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=m;j+=lowbit(j))
for(int k=z;k<=l;k+=lowbit(k))
c[i][j][k]+=w;
}
int sum(int x,int y,int z)
{
int ret=0;
for(int i=x;i>=1;i-=lowbit(i))
for(int j=y;j>=1;j-=lowbit(j))
for(int k=z;k>=1;k-=lowbit(k))
ret+=c[i][j][k];
return ret;
}
int main()
{
cin>>n>>m>>l;
cin>>q;
while(q--)
{
int x;
cin>>x;
if(x==1)
{
int x1,y1,z1,x2,y2,z2,w;
cin>>x1>>y1>>z1>>x2>>y2>>z2>>w;
update(x1,y1,z1,w);
update(x1,y2+1,z1,-w);
update(x2+1,y1,z1,-w);
update(x2+1,y2+1,z1,w);
update(x1,y1,z2+1,-w);
update(x1,y2+1,z2+1,w);
update(x2+1,y1,z2+1,w);
update(x2+1,y2+1,z2+1,-w);
}
if(x==2)
{
int x,y,z;
cin>>x>>y>>z;
cout<<sum(x,y,z)<<endl;
}
}
return 0;
}
练习
校门外的树
描述
校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……
如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:
K=1,K=1,读入l、r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同
K=2,读入l,r表示询问l~r之间能见到多少种树
(l,r>0)
格式
输入格式
第一行n,m表示道路总长为n,共有m个操作
接下来m行为m个操作
输出格式
对于每个k=2输出一个答案
样例1
样例输入1
5 4
1 1 3
2 2 5
1 2 4
2 3 5
Copy
样例输出1
1
2
Copy
限制
1s
提示
范围:20%的数据保证,n,m<=100
60%的数据保证,n <=1000,m<=50000
100%的数据保证,n,m<=50000
来源
dejiyu@CSC WorkGroup
/*************************
User:Mandy.H.Y
Language:c++
Problem:loj10115 tree
Algorithm:
Date:2019.7.13
Scores:
*************************/
//种下一排树,相当于给区间的起点和终点加括号
//可以把数书的种类转化为数括号的个数
// r左边的'['数表示开头到r中树的种类数
// l左边的']'数代表l的左边失去了多少种树
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+5;
int n,m;
long long tree[3][maxn];
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("10115.in","r",stdin);
}
void readdata(){
read(n);read(m);
}
int lowbit(int x){
return x & (-x);
}
void modify(int pos,int x,int id){
for(int i=pos;i<=n;i+=lowbit(i)) tree[id][i]+=x;
}
int query(int pos,int id){
int sum=0;
for(int i=pos;i;i-=lowbit(i)) sum+=tree[id][i];
return sum;
}
void work(){
while(m--){
int k,l,r;
read(k);read(l);read(r);
if(k==1){
modify(l,1,0);
modify(r,1,1);
}
else{
int sum1=query(r,0);
int sum2=query(l-1,1);//l-1
put(sum1-sum2);
putchar('\n');
}
}
}
int main(){
// file();
readdata();
work();
return 0;
}
数星星(Stars)
天空中有一些星星,这些星星都在不同的位置,每个星星有个坐标。如果一个星星的左下方(包含正左和正下)有 k 颗星星,就说这颗星星是 k 级的。
例如,上图中星星 5 是 3级的( 1,2,4在它左下),星星 2,4 是 1 级的。例图中有 1 个 0 级, 2个 1级, 1个 2 级,1 个3 级的星星。
给定星星的位置,输出各级星星的数目。
一句话题意 给定 n 个点,定义每个点的等级是在该点左下方(含正左、正下)的点的数目,试统计每个等级有多少个点。
输入格式
第一行一个整数N ,表示星星的数目;
接下来 N行给出每颗星星的坐标,坐标用两个整数 x,y 表示;
不会有星星重叠。星星按 y坐标增序给出, y坐标相同的按 x 坐标增序给出。
输出格式
N行,每行一个整数,分别是 0级,1 级,2 级,……,N-1 级的星星的数目。
样例
样例输入
5
1 1
5 1
7 1
3 3
5 5
样例输出
1
2
1
1
0
数据范围与提示
对于全部数据 1 <= N <= 1.5* 10 4 , 0 <= x,y <= 3.2 * 104.
/**********************
User:Mandy.H.Y
Language:c++
Problem:loj0114 Stars
Algorithm:树状数组
Date:2019.7.13
Scores:
**********************/
//嗯,坐标轴向上向右为正方向
//本来是按顺序输入,则只用一维即可
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e4+5;
int n,tree[32005],ans[maxn];
struct Node{
int x,y;
}node[maxn];
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("10114.in","r",stdin);
}
void readdata(){
read(n);
}
int lowbit(int x){
return x & (-x);
}
void modify(int pos){
for(int i=pos;i<=32001;i+=lowbit(i)) tree[i]++;
}
int query(int pos){
int sum=0;
for(int i=pos;i;i-=lowbit(i)) sum+=tree[i];
return sum;
}
void work(){
for(int i=1;i<=n;++i){
read(node[i].x);read(node[i].y);
node[i].x++;
//听说树状数组无法维护下标为零的元素 >_<
int cur=query(node[i].x);
ans[cur]++;
modify(node[i].x);
}
for(int i=0;i<n;++i) put(ans[i]),putchar('\n');
}
int main(){
// file();
readdata();
work();
return 0;
}
[SDOI2009]HH的项链
题目传送:luogu1972
题目背景
无
题目描述
HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答……因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
输入输出格式
输入格式:
第一行:一个整数N,表示项链的长度。
第二行:N 个整数,表示依次表示项链中贝壳的编号(编号为0 到1000000 之间的整数)。
第三行:一个整数M,表示HH 询问的个数。
接下来M 行:每行两个整数,L 和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
输出格式:
M 行,每行一个整数,依次表示询问对应的答案。
输入输出样例
输入样例#1: 复制
6
1 2 3 4 3 5
3
1 2
3 5
2 6
输出样例#1: 复制
2
2
4
说明
数据范围:
对于100%的数据,N <= 500000,M <= 500000。
/**********************
User:Mandy.H.Y
Language:c++
Problem:luogu 1972 HH
Algorithm:
Date:2019.7.20
Scores:
**********************/
//不能单步调试的电脑不是好电脑
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 5;
const int maxm = 1e6 + 5;
int n,m,a[maxn];
int ans[maxn];
int pos[maxm];
int tree[maxn],pre[maxn];
struct Query{
int l,r,h;
}q[maxn];
template<class T>inline void read(T &x) {
x = 0;
bool flag = 0;
char ch = getchar();
while( ! isdigit(ch)) flag |= ch == '-',ch = getchar();
while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
if(flag) x = -x;
}
template<class T>void putch(const T x) {
if(x > 9) putch(x / 10);
putchar(x % 10 | 48);
}
template<class T>void put(const T x) {
if(x < 0) putchar('-'),putch(-x);
else putch(x);
}
void file() {
freopen("1972.in","r",stdin);
freopen("1972.out","w",stdout);
}
void readdata() {
read(n);
for(int i = 1; i <= n; ++ i) read(a[i]);
read(m);
for(int i = 1; i <= m; ++ i)
read(q[i].l),read(q[i].r),q[i].h = i;
//离线操作
}
bool cmp(const Query &x,const Query &y) {
if(x.r == y.r) return x.l > y.l;
else return x.r > y.r;
}
int lowbit(int x){
return x & (-x);
}
void modify(int pos,int val){
for(int i = pos;i <= n;i += lowbit(i)){
tree[i] += val;
}
}
int query(int pos){
int sum = 0;
for(int i = pos;i;i -= lowbit(i)){
sum += tree[i];
}
return sum;
}
void init(){
for(int i = 1;i <= n; ++ i){
pre[i] = pos[a[i]];
pos[a[i]] = i;
}//记录下每一种贝壳的最后的位置并记录前一个与他相同的贝壳的位置
for(int i = n;i >= 1; -- i)
if(pos[a[i]] == i) modify(i,1);
//每种贝壳最后出现的位置在树状数组中 +1
// for(int i = 1;i <= n; ++ i) printf("query(%d) = %d\n",i,query(i));
}
void work() {
sort(q + 1,q + m + 1,cmp);//从后往前排
// for(int i = 1;i <= m; ++ i) printf("q[%d].r = %d\n",i,q[i].r);
init();
int j = 1;
for(int i = n;i >= 1; -- i) {
while(q[j].r == i){//当枚举到询问的区间
// printf("q[%d].r = %d,query = %d,q[%d].l = %d,query = %d\n",j,q[j].r,query(q[j].r),j,q[j].l,query(q[j].l));
//注意此处i,j;
ans[q[j].h] = query(q[j].r) - query(q[j].l - 1);
// 种类数 = r前的种类数 - (l - 1)前的种类数
//注意 l - 1
++ j;
//指标后移
}
pos[a[i]] = pre[i];
//这个点已访问过,不再有用,不会再被访问,种类数记在他的前驱身上
if(pos[a[i]]) modify(pos[a[i]],1);
//树状数组不维护0节点
}
for(int i = 1;i <= m; ++ i){
put(ans[i]),putchar('\n');
}//注意按照询问的顺序
}
int main() {
// file();
readdata();
work();
return 0;
}
上帝造题的七分钟
题目传送:luogu4514
题目背景
裸体就意味着身体。
题目描述
“第一分钟,X说,要有矩阵,于是便有了一个里面写满了00的n×mn×m矩阵。
第二分钟,L说,要能修改,于是便有了将左上角为(a,b)(a,b),右下角为(c,d)(c,d)的一个矩形区域内的全部数字加上一个值的操作。
第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作。
第四分钟,彩虹喵说,要基于二叉树的数据结构,于是便有了数据范围。
第五分钟,和雪说,要有耐心,于是便有了时间限制。
第六分钟,吃钢琴男说,要省点事,于是便有了保证运算过程中及最终结果均不超过32位有符号整数类型的表示范围的限制。
第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。”
——《上帝造裸题的七分钟》
所以这个神圣的任务就交给你了。
输入输出格式
输入格式:
输入数据的第一行为X n m,代表矩阵大小为n×mn×m。
从输入数据的第二行开始到文件尾的每一行会出现以下两种操作:
L a b c d delta —— 代表将(a,b),(c,d)(a,b),(c,d)为顶点的矩形区域内的所有数字加上delta。
k a b c d —— 代表求(a,b),(c,d)(a,b),(c,d)为顶点的矩形区域内所有数字的和。
请注意,kk为小写。
输出格式:
针对每个k操作,在单独的一行输出答案。
输入输出样例
输入样例#1: 复制
X 4 4
L 1 1 3 3 2
L 2 2 4 4 1
k 2 2 3 3
输出样例#1: 复制
12
说明
对于10%的数据,1 ≤ n ≤ 16, 1 ≤ m ≤ 161≤n≤16,1≤m≤16, 操作不超过200个.
对于60%的数据,1 ≤ n ≤ 512, 1 ≤ m ≤ 5121≤n≤512,1≤m≤512.
对于100%的数据,1 ≤ n ≤ 2048, 1 ≤ m ≤ 2048, -500 ≤ delta ≤ 500,1≤n≤2048,1≤m≤2048,−500≤delta≤500,操作不超过200000个,保证运算过程中及最终结果均不超过32位带符号整数类型的表示范围。
by XLk
/************************
User:Mandy.H.Y
Language:c++
Problem:luogu4514 God
Algorithm:树状数组
Date:2019.7.17
Score:100
************************/
#include<bits/stdc++.h>
using namespace std;
const int maxn = (1 << 11) + 5;
int n,m;
int a1[maxn][maxn];
int a2[maxn][maxn];
int a3[maxn][maxn];
int a4[maxn][maxn];//开long long 会爆空间
template<class T>inline void read(T &x){
x = 0;bool flag = 0;char ch = getchar();
while( ! isdigit(ch)) flag |= ch == '-',ch = getchar();
while( isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
if(flag)x = -x;
}
template<class T>void putch(const T x){
if(x > 9) putch(x / 10);
putchar(x % 10 | 48);
}
template<class T>void put(const T x){
if(x < 0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("4514.in","r",stdin);
freopen("4514.out","w",stdout);
}
void readdata(){
read(n);read(m);
}
int lowbit(int x){
return x & (-x);
}
void modify(int x,int y,int val){
for(int i = x;i <= n;i += lowbit(i))
for(int j = y;j <= m;j += lowbit(j)){
a1[i][j] += val;
a2[i][j] += val * x;
a3[i][j] += val * y;
a4[i][j] += val * x * y;
}
}
int query(int x,int y){
int sum1 = 0,sum2 = 0,sum3 = 0,sum4 = 0;
for(int i = x;i;i -= lowbit(i))
for(int j = y;j;j -= lowbit(j)){
sum1 += a1[i][j];
sum2 += a2[i][j];
sum3 += a3[i][j];
sum4 += a4[i][j];//一起算,否则会爆时间
}
return sum1 * (x + 1) * (y + 1) -
sum2 * (y + 1) -
sum3 * (x + 1) +
sum4;
}
void work(){
char opt;
int a,b,c,d;
int delta;
while(~scanf("%c",&opt)){
if(opt == 'L'){
read(a);read(b);read(c);read(d);read(delta);
modify(a,b,delta);
modify(c + 1,d + 1,delta);
modify(a,d + 1,-delta);
modify(c + 1,b,-delta);
}else if(opt == 'k'){
read(a);read(b);read(c);read(d);
int ans1 = query(c,d);
int ans2 = query(c,b - 1);
int ans3 = query(a - 1,d);
int ans4 = query(a - 1,b - 1);
put(ans1 - ans2 - ans3 + ans4);putchar('\n');
}
}
}
int main(){
// file();
readdata();
work();
return 0;
}