poj-1037
给出n个星星的坐标,如果一个星星的左下方(包含正左和正下)有k颗星星,就说这颗星星是k级的,统计每个等级有多少个点。这题可用树状数组,对于每个星星按y坐标从小到大排序,相同y坐标按x坐标从小到大排序(题目中数据已经有序),输入顺序已排好序,那么只要依次统计星星i之前x坐标小于等于i.x的星星有多少,即是星星i的级别
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<string>
#include<set>
#include<cmath>
using namespace std;
#define N 15005
#define maxn 32002
int n;
int a[maxn], vis[N];
int lowb(int x) {
return x & (-x);
}
void push_m(int x) {
for (int i = x; i < maxn; i += lowb(i)) {
a[i]++;
}
}
int sear(int x) {
int ans = 0;
for (int i = x; i > 0; i -= lowb(i)) {
ans += a[i];
}
return ans;
}
int main() {
memset(a, 0, sizeof(a));
memset(vis, 0, sizeof(vis));
int x, y;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d%d", &x, &y);
vis[sear(x + 1)]++;
push_m(x+1);
}
for (int i = 0; i < n; i++)
cout << vis[i] << endl;
return 0;
}
poj-3321
题意:一棵树上有n个叉子(其实就是n个节点),再告诉你n-1个线段告诉你是u和v节点相连的,再输入m组操作,有两种操作,当是Q操作时你就要输出对象的节点上有多少个苹果(初始化时每个节点都有苹果),C操作是吃掉苹果或是长出苹果(一个节点只能是有一个苹果或是没有苹果,即:有苹果就是吃掉当前节点的苹果,没苹果就是长出苹果)。
思路:可以把它倒过来就可以用树状数组做了,就是还要用dfs来搜一下每个节点的分支有多少个,开始的时间和结束的时间就可以了。
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<vector>
#include<set>
using namespace std;
#define N 100005
vector<vector<int>>a(N);
int n, m;
int cnt;
int lef[N], rig[N], vis[N];
int c[N];
int lowbit(int x) {
return x & (-x);
}
void put_m(int x,int d) {
while (x <= n) {
c[x] += d;
x += lowbit(x);
}
}
void dfs(int x) {
lef[x] = cnt;
for (int i = 0; i < a[x].size(); i++) {
cnt++;
dfs(a[x][i]);
}
rig[x] = cnt;
}
int sum(int x) {
int res = 0;
while (x > 0) {
res += c[x];
x -= lowbit(x);
}
return res;
}
int main() {
memset(lef, 0, sizeof(lef));
memset(rig, 0, sizeof(rig));
memset(c, 0, sizeof(c));
//memset(vis, 0, sizeof(vis));
int u, v, x;
char temp;
scanf("%d", &n);
for (int i = 0; i < n - 1; i++) {
scanf("%d%d", &u, &v);
a[u].push_back(v);
}
cnt = 1;
dfs(1);
for (int i = 1; i <= n; i++) {
vis[i] = 1;
put_m(i, 1);
}
scanf("%d", &m);
cin.get();
for (int i = 0; i < m; i++) {
scanf("%c%d", &temp, &x);
if (temp == 'Q') {
cout << sum(rig[x]) - sum(lef[x] - 1) << endl;
}
else {
if (vis[x]) {
put_m(lef[x], -1);
vis[x] = 0;
}
else {
put_m(lef[x], 1);
vis[x] = 1;
}
}
cin.get();
}
return 0;
}
poj-2481
题目大意:
给你很多线段的头S和尾E,问每一条线段中包含了多少个线段,(S和E相同不计在内)。这题先一看,完全不知道什么方法,感觉非常的难办。
但是!树状数组可以轻松解决这个问题!!!首先,将她们线段的s和e当做是(s,e)一个点,这样子把所有点画出来,你就会发现一个很神奇的现象,题目要求就会变成:问每一个点的左上角有多少个点?
stars
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
using namespace std;
#define N 100005
struct node {
int s, e, k;
}a[N], b[N];
int c[N], res[N];
int n;
map<pair<int, int>, int>q;
bool cmp(node x, node y) {
if (x.e == y.e) {
return x.s < y.s;
}
return x.e > y.e;
}
int lowbit(int x) {
return x & (-x);
}
void insert(int x, int m) {
for (int i = x; i <= m; i += lowbit(i)) {
c[i] += 1;
}
}
int find(int x, int m) {
int sum = 0;
for (int i = x; i > 0; i -= lowbit(i)) {
sum += c[i];
}
return sum;
}
int main() {
while (scanf("%d", &n)) {
if (n == 0)break;
memset(c, 0, sizeof(c));
int mx = -1;
for (int i = 0; i < n; i++) {
scanf("%d%d", &a[i].s, &a[i].e);
a[i].s += 1;
mx = max(a[i].s, mx);
a[i].k = i;
}
sort(a, a + n, cmp);
insert(a[0].s, mx);
res[a[0].k] = 0;
for (int i = 1; i < n; i++) {
if (a[i].s == a[i - 1].s&&a[i].e == a[i - 1].e) {
res[a[i].k] = res[a[i - 1].k];
insert(a[i].s, mx);
continue;
}
res[a[i].k] = find(a[i].s, mx);
insert(a[i].s, mx);
}
for (int i = 0; i < n; i++) {
if (i == 0)
cout << res[i];
else
cout << " " << res[i];
}cout << endl;
}
return 0;
}
poj-2464
题意:在平面直角坐标系中给你N个点,stan和ollie玩一个游戏,首先stan在竖直方向上画一条直线,该直线必须要过其中的某个点,然后ollie在水平方向上画一条直线,该直线的要求是要经过一个stan之前画过的点。 这时候平面就被分割成了四块,两个人这时候会有一个得分,stan的得分是平面上第1、3象限内的点的个数,ollie的得分是平面上第2、4象限内的点的个数,在统计的时候在所画线上的点都不计算在内。求最终stan使得自己的最差得分最高,并且输出此时ollie的得分。
https://blog.csdn.net/shiqi_614/article/details/8236745