树状数组

HDU 1166 	敌兵布阵 
最简单的树状数组点更新,区间查询
#include<cstdio>
#include<cstring>
using namespace std;

int c[100001];
int n, m;

void add(int k, int s){
	for(int i = k; i <= n; i += i & (-i)){
		c[i] += s;
	}
}

int sum(int k){
	int t = 0;
	for(int i = k; i > 0; i -= i & (-i)){
		t += c[i];
	}
	return t;
}

int main(){
	int T;
	scanf("%d", &T);
	for(int kase = 1; kase <= T; kase++){
		printf("Case %d:\n", kase);
		scanf("%d", &n);
		memset(c, 0, sizeof(c));
		for(int i = 1; i <= n; i++){
			int k;
			scanf("%d", &k);
			add(i,k);
		}
		char s[10];
		int x, y;
		while(scanf("%s", s), s[0] != 'E'){
			scanf("%d%d", &x, &y);
			if(s[0] == 'A') {
				add(x, y);
			}else if(s[0] == 'S'){
				add(x, -y);
			}
			else printf("%d\n", sum(y) - sum(x - 1));
		}
	}
	return 0;
}
/
LightOJ 1112 	Curious Robin Hood  
这道题和上一道相比非常类似
#include<stdio.h>
#include<string.h>
int n;
int c[100010];
int lowbit(int x)
{
	return x&(-x);
}
void update(int pos,int i)
{
	while(pos<=n)
	{
		c[pos]+=i;
		pos+=lowbit(pos); 
	}
}
int sum(int pos)
{
	int ans=0;
	while(pos)
	{
		ans+=c[pos];
		pos-=lowbit(pos);
	 } 
	 return ans;
}
int main()
{
	int T,i,k,t=0,q;
	scanf("%d",&T);
	while(T--)
	{
		memset(c,0,sizeof(c));
		printf("Case %d:\n",++t);
		scanf("%d%d",&n,&q);
		for(i=1;i<=n;i++)
		{
			scanf("%d",&k);
			update(i,k);
		}
		int m,a,b;
		while(q--)
		{
			scanf("%d",&m);
			if(m==1)
			{
				scanf("%d",&a);
				a++;
				printf("%d\n",sum(a)-sum(a-1));
				update(a,sum(a-1)-sum(a));
			}
			else if(m==2)
			{
				scanf("%d%d",&a,&b);
				a++;
				update(a,b);
			}
			else if(m==3)
			{
				scanf("%d%d",&a,&b);
				a++;
				b++;
				printf("%d\n",sum(b)-sum(a-1));
			}
		}
	}
	return 0;
}

LightOJ 1080 	Binary Simulation 
典型的树状数组区间更新点查询,查询的时候是查询的每个点的反转次数,然后再加上初始值即可
对2取余就可以得到答案
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define maxn 500005
#define lowbit(i) (i&(-i))
using namespace std;
int a[maxn], n, len, val;
char ch[maxn];
void update(int pos, int v) {
	while(pos<=len) {
		a[pos] += v;
		pos += lowbit(pos);
	}
}
long long sum (int pos) {
	long long ans = 0;
	while(pos>0) {
		ans += a[pos];
		pos -= lowbit(pos);
	}
	return ans;
}
int main (void) {
	int T, k, kase=0;
	scanf("%d", &T);
	while(T--) {
		printf("Case %d:\n", ++kase);
		memset(a, 0, sizeof(a));
		memset(ch, 0, sizeof(ch));
		scanf("%s", ch+1);
		len = strlen(ch+1);
		char op[15];
		scanf("%d", &k);
		for(int i=1; i<=k; ++i) {
			scanf("%s", op);
			int b, c;
			if(op[0] == 'I') {
				scanf("%d %d", &b, &c);
				update(b, 1);
				update(c+1, -1);
			} else if(op[0] == 'Q') {
				scanf("%d", &b);
				int val = sum(b)+ch[b]-'0';
				if(val%2)
					printf("1\n");
				else
					printf("0\n");
			}
		}
	}

	return 0;
}

LightOJ 1085 	All Possible Increasing Subsequences 
这题就是求这个序列中有多少个上升序列。
开一个数组s,s[i]记作以第i数为结尾的上升序列的个数。
用一个数组a,存储原数据
然后求s[j]时,遍历1~j-1,s[j] = sum(s[i]){1<=i<j, a[i]<a[j]}
但这样一定超时,所以可以使用树状数组维护小于m的数字有多少个。
但又因为每个数字可能太大,所以可以先离散化

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int M = 1e5 + 20;
const LL N = 1000000007;
struct node{
	int x, y, z;
	node(int _x = 0, int _y = 0):x(_x), y(_y){}
	friend bool operator < (const node& a, const node& b){
		return a.x < b.x;
	}
}a[M];
bool cmp(const node& a, const node& b){
	return a.z < b.z;
}
LL C[M];
int n;

inline int LowBit(int x) { return x & (-x);}
inline void Update(int x, LL d){
	while(x <= n){
	    C[x] += d;
	    C[x] %= N;
	    x += LowBit(x);
	}
}
inline LL GetSum(int x){
	LL sum = 0;
	while(x > 0){
	    sum += C[x];
	    sum %= N;
	    x -= LowBit(x);
	}
	return sum;
	}

int main()
{
	int t, cas = 1, m;
	cin >> t;
	while(t--){
	    cin >> m, n = 1;
	    LL ans = 0, buf;
	    for(int i = 1; i <= m; i++) scanf("%d", &a[i].x), a[i].z = i;
	    sort(a+1, a+1+m);
	    for(int i = 1; i <= m; i++){
			if(i > 1 && a[i].x == a[i-1].x) a[i].y = a[i-1].y;
			else a[i].y = n++;
	    }
	    for(int i = 0; i < n+10; i++) C[i] = 0;
	    sort(a+1, a+1+m, cmp);//完成了离散化

	    for(int i = 1; i <= m; i++){
			buf = GetSum(a[i].y - 1)+1;
			ans += buf, ans %= N;
			Update(a[i].y, buf);
	    }
	    printf("Case %d: %lld\n", cas++, ans);   
	}
	return 0;
}


LightOJ 1266 	Points in Rectangle 
一道典型的二维树状数组。
二维树状数组无论代码还是理论都和一维差不多
#include <bits/stdc++.h>
using namespace std;
const int M = 1e+3 + 40;
int n, m;
long long C[M][M];
bool vis[M][M];
inline int LowBit(int x){ return x & (-x);}
inline void Update(int x, int y, int d){
    for(int i = x; i <= n; i += LowBit(i))
        for(int j = y; j <= m; j += LowBit(j))
            C[i][j] += d;
}
inline long long GetSum(int x, int y){
    long long sum = 0;
    for(int i = x; i > 0; i -= LowBit(i))
        for(int j = y; j > 0; j -= LowBit(j))
            sum += C[i][j];
    return sum;
}
 
int main()
{
    int t, cas = 1, d, x1, y1, x2, y2, q;
    long long s;
    cin >> t;
    while(t--){
        printf("Case %d:\n", cas++);
        cin >> q;
        n = m = M - 20;
        memset(vis, false, sizeof(vis));
        memset(C, 0, sizeof(C));
        while(q--){
            scanf("%d", &d);
            if(d){
                scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
                x1++, x2++, y1++, y2++;
                s = GetSum(x2, y2) + GetSum(x1-1, y1-1);
                s -= GetSum(x1-1, y2), s-= GetSum(x2, y1-1);
                printf("%lld\n", s);
            }
            else{
                scanf("%d%d", &x1, &y1), x1++, y1++;
                if(!vis[x1][y1]){
                    vis[x1][y1] = true;
                    Update(x1, y1, 1);
                }
            }
        }
    }
    return 0;
}

HDU 5775 	Bubble Sort 
这道题和逆序数有关,试试找找规律,我以前是靠猜把这题过了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
#define lowbit(x) (x&(-x))
int num[100005],c[100005],res[100005],n;

int getSum(int pos)
{
	int res=0;
	while(pos>0){
		res+=c[pos];
		pos-=lowbit(pos);
	}
	return res;
}

void update(int pos, int val)
{
	while(pos<=n){
		c[pos]+=val;
		pos+=lowbit(pos);
	}
}

int main()
{
	int T,k,i;
	scanf("%d",&T);
	for(k=1;k<=T;k++){
		memset(res,0,sizeof(res));
		memset(c,0,sizeof(c));
		scanf("%d",&n);
		for(i=1;i<=n;i++){
			scanf("%d",&num[i]);
		}
		for(i=1;i<=n;i++){
			update(num[i],1);
			res[num[i]]=i-getSum(num[i]);
			if(num[i]>i) res[num[i]]+=num[i]-i;
		}
		printf("Case #%d:",k);
		for(i=1;i<n;i++) printf(" %d",res[i]);
		printf(" %d\n",res[n]); 
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值