树状数组
单点修改 + 单点查询
楼兰图腾
参考题解
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 2e5+5;
typedef long long LL;
int n;
int a[N];
int treeMessage[N]; //the cnt of i
int ll[N], lg[N], rl[N], rg[N];
int lowbit(int x)
{
return x & (-x);
}
void add(int x, int v)
{
for(; x <= n; x += lowbit(x))
{
treeMessage[x] += v;
}
}
// the sum of treeMessage[i], i: 1~x
int query(int x)
{
int ans = 0;
while(x > 0)
{
ans += treeMessage[x];
x = x - lowbit(x);
}
return ans;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; ++ i)
{
scanf("%d", a+i);
}
for(int i = 1; i <= n; i ++)
{
ll[i] = query(a[i]-1);
lg[i] = i-1 - query(a[i]); //之前有i-1个数,不包括a[i]
add(a[i], 1);
}
memset(treeMessage, 0, sizeof treeMessage);
for(int i = n; i > 0; -- i)
{
rl[i] = query(a[i]-1);
rg[i] = n-i - query(a[i]);
add(a[i], 1);
}
LL ans1 = 0, ans2 = 0;
for(int i = 1; i <= n; ++ i)
{
ans1 += lg[i] * (LL)rg[i];
ans2 += ll[i] * (LL)rl[i];
}
cout << ans1 << " " << ans2 << endl;
return 0;
}
区间修改 + 单点查询
一个简单的整数问题
参考题解
利用差分转换成 单点修改+区间查询
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e5+5;
int n, m;
int d[N]; //差分数组
int tree[N];
int lowbit(int x) // 返回末尾的1
{
return x & -x;
}
//单点修改
void add(int x, int v)
{
for(; x <= n; x+=lowbit(x))
{
tree[x] += v;
}
}
//区间查询1~x
int query(int x)
{
int ans = 0;
while(x>0)
{
ans += tree[x];
x -= lowbit(x);
}
return ans;
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; ++ i)
{
scanf("%d", d+i);
}
int last = 0;
for(int i = 1; i <= n; ++ i)
{
int tp = d[i];
d[i] = d[i] - last;
last = tp;
add(i, d[i]);
}
while (m -- )
{
char op[2];
scanf("%s", op);
if(op[0] == 'C')
{
int l, r, d;
scanf("%d%d%d", &l, &r, &d);
add(l, d);
add(r+1, -d);
}
else
{
int x;
scanf("%d", &x);
cout << query(x) << endl;
}
}
return 0;
}
区间修改 + 区间查询
一个简单的整数问题2
参考题解
利用差分和数学推导改为单点修改和区间查询
链接跳转
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e5+5;
typedef long long LL;
int n, m;
int d[N];
LL tree1[N];
LL tree2[N]; //tree1: d, tree2: d*i
int lowbit(int x)
{
return x&(-x);
}
//下标x处添加v
void add(LL tr[], int x, LL v)
{
for(; x <= n; x+=lowbit(x))
{
tr[x] += v;
}
}
//返回1~x的sum
LL query(int x)
{
int tp = x;
LL sum1 = 0, sum2 = 0;
while(x > 0)
{
sum1 += tree1[x];
sum2 += tree2[x];
x -= lowbit(x);
}
return sum1*(tp+1) - sum2;
}
int main()
{
cin >> n >> m;
int last = 0;
for(int i = 1; i <= n; ++ i)
{
scanf("%d", d+i);
int tp = d[i];
d[i] = d[i] - last;
last = tp;
add(tree1, i, d[i]);
add(tree2, i, i*(LL)d[i]);
}
// for(int i = 1; i <= n; ++ i)
// {
// cout << query(i)-query(i-1) << endl;
// }
while (m -- )
{
char op[2];
int l, r;
scanf("%s%d%d", op, &l, &r);
if(op[0] == 'Q')
{
printf("%lld\n", query(r)-query(l-1));
}
else
{
int d;
scanf("%d", &d);
add(tree1, l, d);
add(tree2, l, l*(LL)d);
add(tree1, r+1, -d);
add(tree2, r+1, (r+1)*(LL)(-d));
}
}
return 0;
}
用01数组动态维护:删除元素 + 查询数量
谜一样的牛
参考题解
从最后一头牛开始从右往左逐个推断每头牛是1n中的多少身高,因为1n中的数会因为往前的原因逐个删掉右边已经计算过的元素,所以1n呈现动态删除。采用树状数组维护1n的01数组表示是否被删除,sum(i)就是i前面的i的个数,用二分查询出sum[t]刚好等于a[i]+1的的t(多个的话选最左边的那个),即是其身高。
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e5+5;
int n;
int lowerCnt[N];
int tree[N];
int lowbit(int x)
{
return x & (-x);
}
//在下标x处+v
void add(int x, int v)
{
for(; x < n; x += lowbit(x))
{
tree[x] += v;
}
}
//1~x的sum
int query(int x)
{
int res =0;
while(x > 0)
{
res += tree[x];
x -= lowbit(x);
}
return res;
}
bool check(int x, int height)
{
if(query(x)>=height)
{
return true;
}
return false;
}
int ans[N];
int main()
{
cin >> n;
for(int i = 2; i <= n; ++ i)
{
scanf("%d", lowerCnt+i);
}
for(int i = 1; i <= n; ++ i)
{
add(i, 1);
}
for(int i = n; i >= 1; -- i)
{
int height = lowerCnt[i] + 1;
//查询sum>=height的最小值
int l = 1, r = n;
while(l < r)
{
int mid = l+r>>1;
if(check(mid, height))
{
r = mid;
}
else
{
l = mid+1;
}
}
ans[i] = l;
add(l, -1);
}
for(int i = 1; i <= n; ++ i)
{
printf("%d\n", ans[i]);
}
return 0;
}








浙公网安备 33010602011771号