题目大意:
夜空中有N颗恒星(N≤100000),每颗恒星具有其坐标(x, y)(0≤x, y≤100000)。现在,天文学家要对这些恒星进行分类,分类的标准如下:对于任意一颗恒星S(x,y),如果存在k颗恒星,其x, y坐标均不大于S,则恒星S属于k类星。
现给出N颗恒星的坐标,要求统计出0~N-1类星的个数。
【输入格式】
输入文件第一行包含一个整数N,表示恒星总数。
接下来的N行每行两个整数表示一颗恒星的坐标。不存在两颗星拥有相同的坐标。
【输出格式】
输出文件包含N行,每行包含一个整数,第i行表示第i-1类星的数量。
解析:
首先按x坐标从小到大排序,x相同则y坐标由小到大,然后从左到右扫描每个点,这样可以保证已经插入树状数组的点都在左侧或正下侧。
然后只需寻找有多少点位于当前点下方,很容易想到树状数组。处理完当前点后,将其按y坐标插入树状数组,即让a[y]加1;
最后注意x++,y++,避免循环卡0
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int maxm=35000+5;
const int maxn=150000+5;
int n,m;
int ans[maxn];
int tree[maxn];
int read()
{
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int lowbit(int x)
{
return x & (-x);
}
void add(int x,int y)
{
for(int i=x;i0;i-=lowbit(i))
{
sum+=tree[i];
}
return sum;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x=read();
int y=read();
x++;
ans[getsum(x)]++;
add(x,1);
}
for(int i=0;i
题目大意:
给出长度为n的序列,每次只能交换相邻的两个元素,问至少要交换几次才使得该序列为递增序列。
解析:还是很好理解,就是求逆序对总数,也可以用归并来做
用树状数组时记得离散化一下(a[ ]数组),不然要炸;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int maxn=500000+5;
int n,m;
int a[maxn];
int tree[maxn];
struct node
{
int mark;
LL value;
}e[maxn];
int read()
{
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
bool cmp(node a,node b)
{
return a.value0;i-=lowbit(i))
{
sum+=tree[i];
}
return sum;
}
int main()
{
while(~scanf("%d",&n) && n)
{
memset(a,0,sizeof(a));
memset(tree,0,sizeof(tree));
for(int i=1;i<=n;i++)
{
scanf("%lld",&e[i].value);
e[i].mark=i;
}
sort(e+1,e+n+1,cmp);
for(int i=1;i<=n;i++)
{
a[e[i].mark]=i;
}
LL ans=0;
for(int i=1;i<=n;i++)
{
add(a[i],1);
ans+=i-getsum(a[i]);
}
printf("%lld\n",ans);
}
return 0;
}
【题目大意】
N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色。但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗?
【输入】
每个测试实例第一行为一个整数N,(N <= 100000).接下来的N行,每行包括2个整数a b(1 <= a <= b <= N)。
当N = 0,输入结束。
【输出】
每个测试实例输出一行,包括N个整数,第I个数代表第I个气球总共被涂色的次数。
解析:比较简单的模板题
很明显的,区间修改+单点查询
add(x,1),add(y+1,-1);
↑↑↑这个样子处理一下就成
最后避雷输出,结尾不能有多余空格
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
//PE一次……
const int maxn=100000+10;
int n,m;
int tree[maxn];
int read()
{
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int lowbit(int x)
{
return x& (-x);
}
void add(int x,int value)
{
for(int i=x;i<=n;i+=lowbit(i))
{
tree[i]+=value;
}
}
int getsum(int x)
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
{
sum+=tree[i];
}
return sum;
}
int main()
{
while(~scanf("%d",&n) && n)
{
memset(tree,0,sizeof(tree));
for(int i=1;i<=n;i++)
{
int x=read();
int y=read();
add(x,1);
add(y+1,-1);
}
printf("%d",getsum(1));
for(int i=2;i<=n;i++)printf(" %d",getsum(i));
cout<
题意:日本岛东海岸与西海岸分别有N和M个城市,现在修高速公路连接东西海岸的城市,求交点个数。
解析:将每条路按x从小到达排序,若x相同,按y从小到大排序.
然后按排序后的公路用树状数组在线更新,求y的逆序数之和即为交点个数。
因为相交的情况必然是在在Li
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int maxn=10000000+4;
int n,m,k;
int tree[1000+10];
struct node
{
int x,y;
}e[maxn];
int read()
{
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
bool cmp(node a,node b)
{
if(a.x==b.x) return a.y0;i-=lowbit(i))
{
sum+=tree[i];
}
return sum;
}
int main()
{
int Case=0;
int t=read();
while(t--)
{
n=read(),m=read(),k=read();
memset(tree,0,sizeof(tree));
for(int i=0;i
题意:
给定一个n*n的矩阵,值全为0.每次更新的话是将(x1,y1)到(x2,y2)子矩阵里面的元素的0变成1,1变成0.
最后查询(x,y)节点的值。
解析:二维树状数组,结果对2取模就行
避雷输出,每一组数据输出之后还要输出空行orz
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
//PE一次
const int maxn=1000+10;
int n,m;
int tree[maxn][maxn];
int read()
{
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int lowbit(int x)
{
return x & (-x);
}
void add(int x,int y,int value)
{
for(int i=x;i<=maxn;i+=lowbit(i))
{
for(int j=y;j<=maxn;j+=lowbit(j))
{
tree[i][j]+=value;
}
}
}
int getsum(int x,int y)
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
{
for(int j=y;j>0;j-=lowbit(j))
{
sum+=tree[i][j];
}
}
return sum;
}
int main()
{
int t=read();
while(t--)
{
memset(tree,0,sizeof(tree));
char op[2];
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%s",op);
if(op[0]=='C')
{
int x1=read(),y1=read();
int x2=read(),y2=read();
x2++,y2++;
add(x1,y1,1);
add(x2,y2,1);
add(x2,y1,-1);
add(x1,y2,-1);
}
else
{
int x=read(),y=read();
printf("%d\n",getsum(x,y)%2);
}
}
cout<
题意:
定义三个操作:
开始的操作为 0 ,初始化 S * S大小的地图,值为0;
操作 1, 输入 X Y A, 将地图中坐标为 (X,Y)的值修改为A;
操作2, 输入 L B R T 查询 区间 (X,Y) L<=X<=R , B<=Y<=T, 输出该矩形区间的和;
操作 3 结束程序;
解析:二维树状数组,点修改+区间查询
随便搞一下就行了
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int maxn=1024+10;
int t,s,h;
LL tree[maxn][maxn];
int read()
{
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int lowbit(int x)
{
return x & (-x);
}
void add(int x,int y,int value)
{
for(int i=x;i<=maxn;i+=lowbit(i))
{
for(int j=y;j<=maxn;j+=lowbit(j))
{
tree[i][j]+=value;
}
}
}
LL getsum(int x,int y)
{
LL sum=0;
for(int i=x;i>0;i-=lowbit(i))
{
for(int j=y;j>0;j-=lowbit(j))
{
sum+=tree[i][j];
}
}
return sum;
}
int main()
{
scanf("%d%d",&t,&s);
memset(tree,0,sizeof(tree));
while(~scanf("%d",&h) && h<3)
{
if(h==1)
{
int x=read(),y=read();
int value=read();
x++,y++;
add(x,y,value);
}
else
{
int x=read(),y=read();
int l=read(),r=read();
l++,r++;
LL ans=getsum(l,r)+getsum(x,y)-getsum(l,y)-getsum(x,r);
printf("%lld\n",ans);
}
}
return 0;
}
题目大意:
给出一颗苹果树,树的主干设为1,每一个分支设为一个数,一直到N,代表这颗苹果树。每个分支上面只能最多有一个苹果,也就是一个枝子上面不可能有两个苹果,另外注意一点,不要把苹果树想象成二叉树,苹果树每个节点可以分出很多叉,应该是多叉树。
输入是叉之间的关系:
1 2
1 3
就是主干上面两个叉分别是2 和3.
定义两种操作:
C j 的意思是如果 j 这个枝子上面有苹果就摘下来,如果没有,那么就会长出新的一个;
Q j 就是问 j 这个叉上面的苹果总数。
解析:
将题意提炼一下,就可以理解为对一段区间,进行点修改(摘下苹果or长出新的)+区间查询(询问苹果总数);
于是就往树状数组上靠
现在要考虑的问题是如何把一个树转化为一维数组
我们可以dfs:
对一棵树进行深搜,然后将深搜的顺序重新标上号,然后放到一个数组中,记下每一个枝子得起始点和终结点,然后就可以用树状数组了
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int maxn=100000+10;
int n,m;
int tot=0;
char op[5];
int edges=0;
int head[maxn];
bool apple[maxn];
int tree[maxn],vis[maxn];
int begin[maxn],end[maxn];
struct node
{
int from,to;
int next;
}e[maxn*2];
int read()
{
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
void addedge(int u,int v)
{
e[tot].from=u;
e[tot].to=v;
e[tot].next=head[u];
head[u]=tot++;
}
void init()
{
tot=0;
memset(vis,0,sizeof(vis));
memset(tree,0,sizeof(tree));
memset(head,-1,sizeof(head));
memset(apple,1,sizeof(apple));
}
int lowbit(int x)
{
return x &(-x);
}
void dfs(int u)
{
edges++;
vis[u]=1;
begin[u]=edges;
for(int i=head[u];~i;i=e[i].next)
{
if(!vis[e[i].to])
{
dfs(e[i].to);
}
}
end[u]=edges;
}
void add(int x,int value)
{
for(int i=x;i<=n;i+=lowbit(i))
{
tree[i]+=value;
}
}
int getsum(int x)
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
{
sum+=tree[i];
}
return sum;
}
int main()
{
init();
scanf("%d",&n);
for(int i=1;i
题意:
给出n头牛的叫声v和坐标x,两头牛如果能够交流则会花费max(v[i],v[j])*abs(x[i]-x[j]),问要使每头牛都能和其它牛交流需要花费多少
解析:
首先将这n头牛按照v值从小到大排序(后面说的排在谁的前面,都是基于这个排序)。这样,排在后面的牛和排在前面的牛讲话,两两之间所用的音量必定为后面的牛的v值。
然后,对于某头牛i来说,只要关心跟排在他前面的牛交流就好了。我们只需快速地求出排在他前面的牛和他之间距离的绝对值之和ans。
然后分两部分来计算,小于X0的,和大于X0的:
求出前面小于X0的坐标数s2,和那些小于X0的坐标之和s1,然后用total记录当前i个x坐标的所有和
距离即为:s2*X0 - s1 + total - s1 - x -(i - count)*X;
实际操作需要两个数组:treedis和treecount,分别表示距离和个数;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int maxn=20000+100;
int n,m;
LL treedis[maxn];
LL treecount[maxn];
struct node
{
int value,pos;
}e[maxn];
int read()
{
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
void init()
{
memset(treedis,0,sizeof(treedis));
memset(treecount,0,sizeof(treecount));
}
bool cmp(node a,node b)
{
return a.value0;i-=lowbit(i))
{
sum+=arr[i];
}
return sum;
}
void solve()
{
init();
LL ans=0;
LL totdis=0;
sort(e,e+n,cmp);//!!!
for(int i=0;i
题意:
给出一组数组v[i],现有两种操作:
1)输出v[a]到v[b]之间的和;
2)让v[a]到v[b]之间的数全都加上c。
解析:区间修改+区间查询的模板题
emmm甩个隔壁友情链接,中间比较详细地讲了一下区间修改+查询的具体证明:一刀九十九级
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int maxn=100000+10;
int n,m;
LL a[maxn];
LL sum[maxn];
LL c1[maxn],c2[maxn];
int read()
{
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
LL lowbit(LL x)
{
return x & (-x);
}
void add(LL *arr,LL x,LL value)
{
for(LL i=x;i<=n;i+=lowbit(i))
{
arr[i]+=value;
}
}
LL getsum(LL x,LL *arr)
{
LL sum=0;
for(LL i=x;i>0;i-=lowbit(i))
{
sum+=arr[i];
}
return sum;
}
int main()
{
char op[5];
n=read(),m=read();
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
sum[i]=sum[i-1]+a[i];
}
LL ans=0;
for(int i=1;i<=m;i++)
{
scanf("%s",op);
if(op[0]=='Q')
{
LL s,t;
scanf("%lld%lld",&s,&t);
ans=sum[t]-sum[s-1];
ans+=(t+1)*getsum(t,c1)-getsum(t,c2);
ans-=(s*getsum(s-1,c1)-getsum(s-1,c2));
printf("%lld\n",ans);
}
else
{
LL s,t,v;
scanf("%lld%lld",&s,&t);
scanf("%lld",&v);
add(c1,s,v);
add(c1,t+1,-v);
add(c2,s,s*v);
add(c2,t+1,-v*(t+1));
}
}
return 0;
}
今天写了一天的树状数组,写完博客后发现也没几道emmm
比较困,写着写着就想摸鱼QAQ
以后再更新——