树状数组题目小结 - 入门篇(模板题)

树状数组题目小结 - 入门篇(模板题)

A. POJ-2352
B. POJ-3067
C. luogu-3368-树状数组 2
D. hdu-1166-敌兵布阵
E. hdu-1556-Color the ball
F. POJ-3468
G. POJ-2481
H. POJ -2299
I. POJ -1990
J. POJ-2155
K. POJ-3321

A. POJ-2352
点修改 + 区间和

/*
nero
2019-8-20 20:39:45 
1A 
*/

#include  
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include 

using namespace std;

#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair
typedef long long ll;
typedef unsigned long long ull;

const int MAXN = 15005;
int n,m;
int c[32005], ans[MAXN];

int lowbit(int x) {
	return x & (-x);
}
void update(int x) {
	int i = x;
	while(i <= 32001) {
		c[i]++;
		i += lowbit(i);
	}
	return;
}
int Query(int x) {
	int i = x;
	int sum = 0;
	while(i >= 1) { // 把 0 加了 1 
		sum += c[i];
		i -= lowbit(i);
	}
	return sum;
}
int main() {
	int T;
	int x,y;
	scanf("%d", &n);
	for(int i = 1; i <= 32001; i++) c[i] = 0;
	for(int i = 1; i <= n; i++) {
		scanf("%d%d", &x, &y);
		x++,y++;
		ans[Query(x)]++;
		update(x);		
	}
	for(int i = 0; i < n; i++) {
		printf("%d\n", ans[i]);
	}
	return 0;
} 

B. POJ-3067
点修改+区间和

/*
nero
2019-8-20 17:40 
long long WA1 
*/

#include  
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include 

using namespace std;

#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair
typedef long long ll;
typedef unsigned long long ull;

const int MAXN = 1005;
int n,m;
ll c[MAXN];
struct node {
	int x, y;
	bool operator<(const node &B)const {
		return x == B.x ? y < B.y : x < B.x;
	}
}a[MAXN * MAXN];
int lowbit(int x) {
	return x & (-x);
}
void update(int x) {
	int i = x;
	while(i <= m) {
		c[i]++;
		i += lowbit(i);
	}
	return;
}
ll Query(int x) {
	int i = x;
	ll sum = 0;
	while(i >= 1) {
		sum += c[i];
		i -= lowbit(i);
	}
	return sum;
}
int main() {
	int T, K;
	scanf("%d", &T);
	for(int tt = 1; tt <= T; tt++) {
		
		scanf("%d%d%d", &n, &m, &K);
		for(int i = 1; i <= m; i++) c[i] = 0;
		for(int i = 1; i <= K; i++) {
			scanf("%d%d", &a[i].x, &a[i].y);
		}
		sort(a + 1, a + K + 1);
		ll ans = 0;
		for(int i = K; i >= 1; i--) {
			ans +=  Query(a[i].y - 1);
			update(a[i].y);
		}
		printf("Test case %d: %lld\n",tt, ans);
	}
	return 0;
} 

C. luogu-3368-树状数组 2
区间加+点查询

/*
nero
 
*/

#include  
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair
typedef long long ll;
typedef unsigned long long ull;

const int MAXN = 500005;
int n, m;
ll c[MAXN<<2], a[MAXN];
int lowbit(int x) {
	return x&(-x);
}
void update(int k, ll x) {
	for(int i = k; i <= n; i += lowbit(i)) {
		c[i] += x;
	}
	return;
}
ll Query_sum(int k) {
	ll sum = 0;
	for(int i = k; i >= 1; i -= lowbit(i)) {
		sum += c[i];
	}
	return sum;
}
int main() {
	int l, r, op;
	ll k;
	a[0] = 0;
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]);
		update(i,a[i] - a[i-1]);
	}
	while(m--) {
		scanf("%d", &op);
		if(op == 1) {
			scanf("%d%d%lld", &l, &r, &k);
			update(l, k);
			update(r+1, -k);
		}
		else {
			scanf("%d", &l);
			printf("%lld\n", Query_sum(l));
		}
	}
	
	return 0;
} 

D. hdu-1166-敌兵布阵
单点修改+区间和
前两天做线段树刚刚做过,又遇到了。

#include  
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair
typedef long long ll;
typedef unsigned long long ull;

const int MAXN = 50005;
int n;
int c[MAXN << 2], a[MAXN];
int lowbit(int x) {
	return x&(-x);
}
void update(int i, int x) {
	for(int k = i; k <= n; k += lowbit(k)) {
		c[k] += x;
	}	
}
int Query_sum(int i) {
	int ans = 0;
	for(int k = i; k >= 1; k -= lowbit(k)) {
		ans += c[k];
	}
	return ans;
}
int main() {
	int T, x, i, l, r;
	char op[10];
	scanf("%d", &T);
	for(int tt = 1; tt <= T; tt++){
		printf("Case %d:\n",tt);
		scanf("%d", &n);
		for(int i = 1; i <= n*4; i++) {
			c[i] = 0;
		}
		for(int i = 1; i <= n; i++) {
			scanf("%d", &a[i]);
			update(i, a[i]);
		}
		while(scanf("%s",op) != EOF) {
			if(op[0] == 'E') break;
			if(op[0] == 'A') {
				scanf("%d%d", &i, &x);
				update(i,x);
			}
			if(op[0] == 'S') {
				scanf("%d%d", &i, &x);
				update(i,-x);
			}
			if(op[0] == 'Q') {
				scanf("%d%d", &l, &r);
				printf("%d\n",Query_sum(r) - Query_sum(l-1));
			}
		}
	} 
	return 0;
}

E. hdu-1556-Color the ball
区间加 + 单点查询

/*
nero
2019-8-17 11:07:15
*/

#include  
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair
typedef long long ll;
typedef unsigned long long ull;

const int MAXN = 100005;
int n;
int c[MAXN];
int lowbit(int x) {
	return x&(-x);
}
void update(int k, int x) {
	for(int i = k; i <= n; i += lowbit(i)) {
		c[i] += x;
	}
	return;
}
ll Query_sum(int k) {
	ll sum = 0;
	for(int i = k; i >= 1; i -= lowbit(i)) {
		sum += c[i];
	}
	return sum;
}
int main() {
//	freopen("in.txt", "r", stdin);
	int l, r;
	while(scanf("%d", &n) != EOF) {
		if(n == 0) break;
		for(int i = 0; i <= n; i++) c[i] = 0;
		for(int i = 1; i <= n; i++) {
			scanf("%d%d", &l, &r); 
			update(l, 1);
			update(r+1, -1);
		}
		for(int i = 1; i <= n; i++) {
			printf("%d", Query_sum(i));
			if(i < n) printf(" ");
		}
		printf("\n");		
	} 
	return 0;
} 
/*

*/

F. POJ-3468
区间加 + 区间和

/*
nero
2019-8-23 20:43:49

*/

#include  
#include 
#include 
#include 
#include 
#include 
#include 
//#include 

using namespace std;

#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair
typedef long long ll;
typedef unsigned long long ull;

const int MAXN = 100005;
int n, m;
ll sum1[MAXN], a[MAXN], sum2[MAXN];
int lowbit(int x) {
	return x&(-x);
}
void update(int k, ll x) {
	for(int i = k; i <= n; i += lowbit(i)) {
		sum1[i] += x;
		sum2[i] += x * k;
	}
	return;
}

ll Query_sum(int k) {
	ll sum = 0;
	for(int i = k; i >= 1; i -= lowbit(i)) {
		sum += sum1[i] * (k + 1) - sum2[i];
	}
	return sum;
}
int main() {
	int l, r;
	char op[2];
	ll k, all = 0;
	a[0] = 0;
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]);
		update(i,a[i] - a[i-1]);
	}                                                                          
	while(m--) {
		scanf("%s", &op);
		if(op[0] == 'C') {
			scanf("%d%d%lld", &l, &r, &k);
			update(l, k);
			update(r+1, -k);
		}
		else {
			scanf("%d%d", &l, &r);
			all = Query_sum(r) - Query_sum(l-1);
			printf("%lld\n", all);
		}
	}	
	return 0;
} 

G. POJ-2481
           \;\;\;\;\; 区间覆盖,点修改+区间和
           \;\;\;\;\; 按照左端点由小到大排序,每次只要看前面有多少右端点比当前的右端点大,最后更新右端点的值。
           \;\;\;\;\; 有个需要注意的地方就是,两个区间可能会重合。这个时候就不能算。
           \;\;\;\;\; 这个题有点玄学,按照我的写法,行末不输出多余的空格,在G++里面会T,C++可过。换种写法也可过。听学长说一般不用注意这个点。

/*
nero
2019-8-23 21:21:30 
*/

#include  
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include 

using namespace std;

#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair
typedef long long ll;
typedef unsigned long long ull;

const int MAXN = 100005;

struct node {
	int l, r;
	int p;
	bool operator < (const node &B) const {
		return l == B.l ? r > B.r : l < B.l;
	}
}t[MAXN];
int n, Max;
int c[MAXN], ans[MAXN];
int lowbit(int x) {
	return x & (-x);
}
void update(int k) {
	for(int i = k; i <= Max; i += lowbit(i)) {
		c[i]++;
	}
	return;
}
int Query_sum(int k) {
	int sum = 0;
	for(int i = k; i >= 1; i -= lowbit(i)) {
		sum += c[i];
	}
	return sum;
}
int main() {
	while(scanf("%d",&n) != EOF) {
		if(n == 0) break;
		Max = 0;
		for(int i = 1; i <= n; i++) {
			scanf("%d%d", &t[i].l, &t[i].r);
			t[i].l++, t[i].r++;
			Max = max(Max, t[i].r);
			t[i].p = i;
		}
		sort(t + 1, t + n + 1);
		for(int i = 1; i <= Max; i++) c[i] = 0;
		for(int i = 1; i <= n; i++) {
			if(i > 1 && t[i].l == t[i-1].l && t[i].r == t[i-1].r) {
				ans[t[i].p] = ans[t[i-1].p];
			}
			else ans[t[i].p] = (i-1) - Query_sum(t[i].r-1);
			update(t[i].r);
		}
		for(int i = 1; i <= n; i++) { // 这里交 G++ 会 T,C++ 可过 
			printf("%d", ans[i]);
			if(i < n) printf(" ");
		}
		printf("\n");
	}
	return 0;
} 

H. POJ -2299
           \;\;\;\;\; 点修改+区间和
           \;\;\;\;\; 求逆序对,离散化,去重用了 unique 函数

/*
nero
2019-8-17 10:18:08 
*/

#include  
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include 

using namespace std;

#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair
typedef long long ll;
typedef unsigned long long ull;

const int MAXN = 500005;
int n;
int c[MAXN], a[MAXN];
vectorv;
int lowbit(int x) {
	return x&(-x);
}
void update(int k, int x) {
	for(int i = k; i <= n; i += lowbit(i)) {
		c[i] += x;
	}
	return;
}
ll Query_sum(int k) {
	ll sum = 0;
	for(int i = k; i >= 1; i -= lowbit(i)) {
		sum += c[i];
	}
	return sum;
}
int main() {
//	freopen("in.txt", "r", stdin);
	while(scanf("%d", &n) != EOF) {
		if(n == 0) break;
		v.clear();
		ll ans = 0;
		for(int i = 1; i <= n; i++) {
			scanf("%d", &a[i]);
			v.push_back(a[i]);
			c[i] = 0;
		}
		sort(v.begin(), v.end());
		unique(v.begin(),v.end()); // 去重 
		for(int i = n; i >= 1; i--) {
			int p = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1;
			ans += Query_sum(p-1);
			update(p,1);
		}
		printf("%lld\n", ans);
	} 
	return 0;
} 

I. POJ -1990
           \;\;\;\;\; 点修改+区间和
           \;\;\;\;\; 这个题需要推一下。
           \;\;\;\;\; a n s = ∑ i = 1 n ∑ j = 1 i − 1 m a x ( v i , v j ) ⋅ ∣ x i − x j ∣ ans = \sum_{i=1}^{n}\sum_{j=1}^{i-1}max(v_{i}, v_{j}) \cdot |x_{i} - x_{j}| ans=i=1nj=1i1max(vi,vj)xixj, 答案里面有两个因素,一个是阈值,一个是距离。某一个元素 ( v i , x i ) (v_{i}, x_{i}) (vi,xi) 对于答案的贡献有多少,要看其它元素 v j v_{j} vj v i v_{i} vi 的大小关系。只要对于每个元素,求出它关于那些 v j < v i v_{j} < v_{i} vj<vi 的元素的贡献就好。比它大的会在大的那里求。
           \;\;\;\;\; 对于所有 v j < v i v_{j} < v_{i} vj<vi 的元素,答案就是 ∑ v i ⋅ ∣ x i − x j ∣ \sum v_{i} \cdot |x_{i} - x_{j}| vixixj,其中 v i v_{i} vi 可以提取出来,这样就是求 ∑ ∣ x i − x j ∣ \sum |x_{i} - x_{j}| xixj
           \;\;\;\;\; 对于 x i > x j x_{i} > x_{j} xi>xj 的元素, ∑ ∣ x i − x j ∣ = ∑ x i − ∑ x j = c n t 1 ⋅ x i − ∑ x j \sum |x_{i} - x_{j}| = \sum x_{i} - \sum x_{j} = cnt1 \cdot x_{i} - \sum x_{j} xixj=xixj=cnt1xixj,其中 c n t 1 cnt1 cnt1 x i > x j x_{i} > x_{j} xi>xj 的数量;
           \;\;\;\;\; 对于 x i < x j x_{i} < x_{j} xi<xj 的元素, ∑ ∣ x i − x j ∣ = ∑ x j − ∑ x i = ∑ x j − c n t 2 ⋅ x i \sum |x_{i} - x_{j}| = \sum x_{j} - \sum x_{i} = \sum x_{j} - cnt2 \cdot x_{i} xixj=xjxi=xjcnt2xi,其中 c n t 2 cnt2 cnt2 x i < x j x_{i} < x_{j} xi<xj 的数量;
           \;\;\;\;\; 用树状数组维护每个 x i x_{i} xi数量 以及 前缀和 就好。

/*
nero
2019-8-26 10:27:12 
long long 用了 %d WA1 
*/

#include  
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include 

using namespace std;

#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair
typedef long long ll;
typedef unsigned long long ull;

const int MAXN = 20005;

using namespace std;
int n;
ll sum1[MAXN], sum2[MAXN];
struct node {
	ll x, c;
	bool operator < (const node &B) const {
		return c < B.c;
	} 
}a[MAXN];

int lowbit(int x) {
	return x & (-x);
}
void update(int k, int x, ll sum[]) {
	int i = k;
	while(i < MAXN) {
		sum[i] += x;
		i += lowbit(i);
	}
	return;
}
ll Query(int k, ll sum[]) {
	ll ans = 0;
	int i = k;
	while(i > 0) {
		ans += sum[i];
		i -= lowbit(i);
	}
	return ans;
}
int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) {
		scanf("%lld%lld", &a[i].c, &a[i].x);
	}
	sort(a + 1, a + n + 1);
	ll sumx = 0, ans = 0;
	for(int i = 1; i <= n; i++) {
		ll cnt1 = Query(a[i].x, sum1), cnt2 = i - 1 - cnt1;
		ll pre = Query(a[i].x, sum2);
		ll dis = a[i].x * cnt1 - pre + sumx - pre - cnt2 * a[i].x;
		ans += a[i].c * dis;
		sumx += a[i].x;
		update(a[i].x, 1, sum1); // 个数 
		update(a[i].x, a[i].x, sum2);
	}
	printf("%lld\n", ans);
	return 0; 
} 

J. POJ-2155
           \;\;\;\;\; 操作1:在一个矩阵里面,元素有两种状态,每次改变一个矩形内的元素的状态。
           \;\;\;\;\; 操作2:查询某点状态。
           \;\;\;\;\; 简单的二维树状数组
           \;\;\;\;\; 区间加+单点查询

/*
nero
2019-8-20 16:49:18 
数组清空 WA1
格式错误 WA1 
*/

#include  
#include 
#include 
#include 
#include 
#include 
#include 
//#include 

using namespace std;

#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair
typedef long long ll;
typedef unsigned long long ull;

const int MAXN = 1005;

int n;
int c[MAXN][MAXN];
int lowbit(int x) {
	return x & (-x);
}
void update(int x, int y) {
	int i = x;
	while(i <= n) {
		int j = y;
		while(j <= n) {
			c[i][j]++, j += lowbit(j);
		}
		i += lowbit(i);
	}
	return;
}
int Query(int x, int y) {
	int sum = 0;
	int i = x;
	while(i >= 1) {
		int j = y;
		while(j >= 1) {
			sum += c[i][j], j -= lowbit(j);
		}
		i -= lowbit(i);
	}
	return sum;
}
int main() {
	int T, Q;
	int x1, y1, x2, y2, x, y;
	char op[3];
	scanf("%d", &T);
	while(T--) {
		memset(c,0,sizeof(c));
		scanf("%d%d", &n, &Q);
		while(Q--) {
			scanf("%s", op);
			if(op[0] == 'C') {
				scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
				update(x1,y1);
				update(x1,y2+1);
				update(x2+1,y1);
				update(x2+1,y2+1);
			}
			else {
				scanf("%d%d", &x, &y);
				int sum = Query(x,y);
				printf("%d\n", sum & 1);
			}
		}
		if(T) printf("\n");
	}	
	return 0;
} 

K. POJ-3321
           \;\;\;\;\; dfs+单点修改+区间和
           \;\;\;\;\; 一开始想的是,每dfs一下,每次改变状态的时候只要更新其父节点即可。T了一发后才想到,一条链岂不是。。。
           \;\;\;\;\; 用 dfs 给点重新编号,寻找一个点的子树中编号最小和最大的点,就得到了这个点的左右区间,(感觉有点像多叉的线段树),问某个子树的苹果数量就变成了求区间和。
           \;\;\;\;\; 这个题卡vector,改成数组之后就过了,不过评论里面说,用 vector < vector >int 也可过。(连续两天连续卡两个题真的很难受)

/*
nero
2019-8-23 23:47:37
dfs 会 T, 只有一条链 
vector 会 T,用数组 
*/

#include  
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include 

using namespace std;

#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair
typedef long long ll;
typedef unsigned long long ull;

const int MAXN = 1000005;
int n, cnt = 1, num = 1;

int l[MAXN], r[MAXN], c[MAXN], a[MAXN], head[MAXN];

struct edge {
	int x, y, nxt;
}Edge[MAXN << 1];
void Add_edge(int x, int y) {
	Edge[num].x = x;
	Edge[num].y = y;
	Edge[num].nxt = head[x];
	head[x] = num++;
	
}
void dfs(int x, int fa) {
	for(int i = head[x] ; i != -1; i = Edge[i].nxt) {
		int xx = Edge[i].y;
		if(xx == fa) continue;
		l[xx] = r[xx] = ++cnt; 
		dfs(xx, x); 
		r[x] = max(r[x], r[xx]);
	}
	return;
}

int lowbit(int x) {
	return x & (-x);
}
void update(int k, int x) {
	while(k <= n) {
		c[k] += x;
		k += lowbit(k);
	}
	return;
}
int Query_sum(int k) {
	int sum = 0;
	while(k) {
		sum += c[k];
		k -= lowbit(k);
	}
	return sum;
}

int main() {
	char op[3];
	int k, x, y, m;
	while(scanf("%d", &n) != EOF) {
		num = 1;
		for(int i = 1; i <= n; i++) {
			c[i] = 0;
			l[i] = r[i] = 0;
			head[i] = -1;
		}		
		for(int i = 1; i < n; i++) {
			scanf("%d%d", &x, &y);
			Add_edge(x,y);
			Add_edge(y,x);
		}

		cnt = 1;
		l[1] = r[1] = 1;
		dfs(1, 0);	
		for(int i = 1; i <= n; i++) {
			a[i] = 1;
			update(l[i], 1);
		}
		scanf("%d", &m);
		while(m--) {
			scanf("%s%d", op, &k);
			if(op[0] == 'C') {
				if(a[k] == 0) update(l[k], 1);
				else update(l[k], -1);
				a[k] = 1 - a[k]; 
			}
			else printf("%d\n", Query_sum(r[k]) - Query_sum(l[k]-1));
		}	
	}
	
	return 0;
}

题目参考:【140508专题】树状数组——题目集

你可能感兴趣的:(数据结构-树状数组)