HDU 1556 Color the ball
/一位树状数组板子题(但c[]已经不是定义上的数组了,但是很常用)
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n;
int c[maxn];
int lowbit(int x)
{
return x&-x;
}
void update(int pos,int val)
{
while(pos>0)
{
c[pos]+=val;
pos-=lowbit(pos);
}
}
int getsum(int num)
{
int sum=0;
while(num<=n)
{
sum+=c[num];
num+=lowbit(num);
}
return sum;
}
int main()
{
int a,b;
while(~scanf("%d",&n)&&n)
{
memset(c,0,sizeof(c));
for(int i=0;i<n;i++)
{
scanf("%d%d",&a,&b);
update(b,1);
update(a-1,-1);
}
for(int i=1;i<n;i++)
{
printf("%d ",getsum(i));
}
printf("%d\n",getsum(n));
}
}
POJ 1195 Mobile phones
二维树状数组纯板子题
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int ca, s, op;
int c[1100][1100];
void add(int i, int j, int v)
{
while(i <= s)
{
int y = j;
while(y <= s)
{
c[i][y] += v;
y += y&-y;
}
i += i&-i;
}
}
int query(int i,int j)
{
int ans = 0;
while(i > 0)
{
int y = j;
while(y > 0)
{
ans += c[i][y];
y -= y&-y;
}
i -= i&-i;
}
return ans;
}
int main()
{
cin >> ca >> s;
while(1)
{
scanf("%d", &op);
if(op == 1)
{
int a, b, v;
scanf("%d%d%d", &a, &b, &v);
add(a+1, b+1, v);
}
else if(op == 2)
{
int x1, x2, y1, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
int ans = query(x2+1, y2+1) + query(x1, y1) - query(x2+1, y1) - query(x1, y2+1);
printf("%d\n", ans);
}
else break;
}
}
POJ 3321
题意:
给出一个苹果树,每个节点一开始都有苹果
C X,如果X点有苹果,则拿掉,如果没有,则新长出一个
Q X,查询X点与它的所有后代分支一共有几个苹果
用到了dfs序,第一次学。
复制一下大佬们的思路:
思路很巧妙,我们通过自己来编号所有苹果,每个节点保存两个值,左值为本身,右值为其包含的所有后代中最大的编号
我们可以通过搜索来进行编号,在编好号之后,我们可以知道,对于某一点而言,我们是先通过这个点搜完所有他的后代编号才结束的,所以这个点的右值,包含了当前点所有的后代与祖先,后代必然是所有编号大于本节点的点,那么祖先呢,那必然是编号小于这个节点的点了
所以我们通过sum(rig[x])-sum(lef[x]-1)就能得到查询的答案
至于更新,只需要更新当前点即可,这样就转化为树状数组了
#include<stdio.h>
#include<string.h>
#include<cstring>
using namespace std;
const int maxn=210100;
struct node
{
int to;
int next;
}e[maxn];
char s;int x;
int in[maxn],out[maxn],c[maxn],cnt=0;
int n,m,tot=0,head[maxn],vis[maxn];
void edd_edge(int u,int v)
{
tot++;
e[tot].to=v;
e[tot].next=head[u];
head[u]=tot;
}
int lowbit(int x)
{
return x&(-x);
}
void dfs(int x)
{
in[x]=++cnt;
for(int i=head[x];i;i=e[i].next)
dfs(e[i].to);
out[x]=cnt;
}
void update(int x,int add)
{
while(x<=n)
{
c[x]+=add;
x+=lowbit(x);
}
}
int sum(int x)
{
int s=0;
while(x>0)
{
s+=c[x];
x-=lowbit(x);
}
return s;
}
int main()
{
int a,b;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
edd_edge(a,b);
}
dfs(1);
for(int i=1;i<=n;i++)
update(in[i],1),vis[i]=1;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%s%d",&s,&x);
if(s=='C')
{
if(vis[x])update(in[x],-1);
else update(in[x],1);
vis[x]=1-vis[x];
}
if(s=='Q')
printf("%d\n",sum(out[x])-sum(in[x]-1));
}
return 0;
}
题意:
在坐标上有n个星星,如果某个星星坐标为(x, y), 它的左下位置为:(x0,y0),x0<=x 且y0<=y。如果左下位置有a个星星,就表示这个星星属于level x,按照y递增,如果y相同则x递增的顺序给出n个星星,求出所有level水平的数量。
思路:
因为输入是按照按照y递增,如果y相同则x递增的顺序给出的, 所以,对于第i颗星星,它的level就是之前出现过的星星中,横坐标x小于等于i星横坐标的那些星星的总数量(前面的y一定比后面的y小)。所以,需要找到一种数据结构来记录所有星星的x值,方便的求出所有值为0~x的星星总数量。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 32005
int c[maxn];
int levels[maxn];
int lowbit(int x)
{
return x&(-x);
}
int sum(int x)
{
int res=0;
while(x>0)
{
res+=c[x];
x-=lowbit(x);
}
return res;
}
void update(int pos)
{
while(pos<=32001)
{
c[pos]++;
pos+=lowbit(pos);
}
}
int main()
{
int n,x,y;
while(~scanf("%d",&n))
{
memset(levels,0,sizeof(levels));
for(int i=1; i<=n; i++)
{
scanf("%d%d",&x,&y);
levels[sum(x+1)]++;
update(x+1);
}
for(int i=0; i<n; i++)
printf("%d\n",levels[i]);
}
}