先贴一些新的树状数组的东西。。当然都是各处ctrl+c来的……
适用范围:
1 下标要从1开始
2 常用于修改一个点a[i],查询区间和的情况c[i]
3 适用范围是必须符合减法原则,也就是说不能用于求一个区间范围内的最值
k&(-k):将k化为二进制时末尾0的个数模版:
int lowbit(int x)//计算lowbit
{
return x&(-x);
}
void add(int i,int val)//将第i个元素更改为val
{
while(i<=n)
{
c[i]+=val;
i+=lowbit(i);
}
}
int sum(int i)//求前i项和
{
int s=0;
while(i>0)
{
s+=c[i];
i-=lowbit(i);
}
return s;
}
差不多就这样,以后看到继续补充吧。
上新题:
Cube |
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others) |
Total Submission(s): 22 Accepted Submission(s): 19 |
Problem Description
Given an N*N*N cube A, whose elements are either 0 or 1. A[i, j, k] means the number in the i-th row , j-th column and k-th layer. Initially we have A[i, j, k] = 0 (1 <= i, j, k <= N).
We define two operations, 1: “Not” operation that we change the A[i, j, k]=!A[i, j, k]. that means we change A[i, j, k] from 0->1,or 1->0. (x1<=i<=x2,y1<=j<=y2,z1<=k<=z2). 0: “Query” operation we want to get the value of A[i, j, k]. |
Input
Multi-cases.
First line contains N and M, M lines follow indicating the operation below. Each operation contains an X, the type of operation. 1: “Not” operation and 0: “Query” operation. If X is 1, following x1, y1, z1, x2, y2, z2. If X is 0, following x, y, z. |
Output
For each query output A[x, y, z] in one line. (1<=n<=100 sum of m <=10000)
|
Sample Input
2 5 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 2 2 2 0 1 1 1 0 2 2 2 |
Sample Output
1 0 1 |
三维的树状数组。想法很奇妙,将区间修改点查询硬是绕回了点修改区间查询。
粘贴党:
每次修改的时候,给定一个格子修改的范围(x,y)。把这个范围变成两个点,一个为更改的初始节点x,另一个为终止结点y+1(不是y),然后这两个节点加1,向根节点上溯,节点+1。
x y+1
0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
三维即需要改8个点。insert x,y+1
每次询问x的时候只需计算sum=sigma(a[i],0<i<=x),即第x个数被修改了sum次,状态为sum%2。
#include <iostream>
using namespace std;
int n;
int c[102][102][102];
int lowbit(int x)//计算lowbit
{
return x&(-x);
}
void add(int x,int y,int z)//将第i个元素更改为val
{
int yy=y,zz=z;
for(;x<=n;x+=lowbit(x))
for(y=yy;y<=n;y+=lowbit(y))
for(z=zz;z<=n;z+=lowbit(z))
c[x][y][z]^=1;//c=!c
}
int sum(int x,int y,int z)//求前i项和
{
int s=0;
int yy=y,zz=z;
for(;x>0;x-=lowbit(x))
for(y=yy;y>0;y-=lowbit(y))
for(z=zz;z>0;z-=lowbit(z))
//s=(s+c[x][y][z])&1;
s^=c[x][y][z];
cout<<s<<endl;
}
int main()
{
int m;
while(cin>>n>>m)
{
memset(c,0,sizeof(c));
while(m--)
{
int s;
int x1,y1,z1,x2,y2,z2;
scanf("%d",&s);
if(s)
{
scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
add(x1,y1,z1);//eight point
add(x1,y2+1,z1);
add(x1,y2+1,z2+1);
add(x1,y1,z2+1);
add(x2+1,y1,z1);
add(x2+1,y2+1,z1);
add(x2+1,y2+1,z2+1);
add(x2+1,y1,z2+1);
}
else
{
scanf("%d%d%d",&x1,&y1,&z1);
sum(x1,y1,z1);
}
}
}
return 0;
}
直接拿模版改得,感觉不错。不过还是有些小问题。
由于三重循环懒得打了经常会复制粘贴,修改时要注意细节。不要漏改了一些地方害的调代码半天。
三重循环时x可以直接减,但y和z都要循环几次,需要保留变量y,z的值。显然我是事后改得,用yy,zz保留值。其实比较正常的思路是用yy,zz做循环变量吧……不过现在这样可以少敲几个y和z……要不要这么懒啊喂!
不管怎样,树状数组的基础题会做了,撒花~