J.farm(二维树状数组)
题意:给一个n*m的矩阵,每个格子里面都有一种植物(类型可能不同),进行q次操作,每次往给出的区域里面浇灌一种类型农药,如果农药和植物的类型不一样这个植物就会死掉,问进行了所有的操作以后死掉的植物的种类。
题解:本来以为用二维树状数组或者线段树都会T所以比赛时候就没有做,但赛后发现都是可行的。每次喷农药的时候将这个区间内的植物的贡献都加一。 然后对于[1,n*m]的所有植物, 先删除同种植物的同种农药对区间的影响, 然后查询该种植物的是否被标记过了 即 该位置的值 > 1, 最后处理完这种植物再把这种植物的农药再加回去。
附上代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod=1000000007;
const int maxn = 1e6 + 100;
vector<int> s[maxn];
vector<pll> q[maxn];
int n, m;
struct node
{
int x1, y1, x2, y2, k;
bool operator<(const node&aa)const
{
return aa.k>k;
}
}a[maxn];
int lowbit(int x)
{
return x&(-x);
}
void add(int x, int y, int c)
{
for(int i = x; i <= n; i+=lowbit(i))
for(int j = y; j <= m; j += lowbit(j))
s[i][j] += c;
}
int query(int x, int y)
{
int cnt = 0;
for(int i = x; i > 0; i -= lowbit(i))
for(int j = y; j > 0; j -= lowbit(j))
cnt += s[i][j];
return cnt;
}
int main()
{
int t, v;
int ans = 0;
scanf("%d%d%d", &n, &m, &t);
for(int i = 1; i <= n; i++)
s[i].resize(m+10);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
scanf("%d", &v);
q[v].push_back(pll(i,j));
}
}
for(int i = 1; i <= t; i++)
{
scanf("%d%d%d%d%d", &a[i].x1, &a[i].y1, &a[i].x2, &a[i].y2, &a[i].k);
add(a[i].x1, a[i].y1, 1);
add(a[i].x2+1,a[i].y2+1,1);
add(a[i].x1,a[i].y2+1,-1);
add(a[i].x2+1,a[i].y1,-1);
}
sort(a+1,a+1+t);
for(int i = 1, j = 1, zz; i <= n * m; i++)
{
while(a[j].k < i && j <= t) j++;
if(q[i].size() == 0) continue;
zz = j;
while(a[zz].k == i && zz <=t) zz++;
for(int z = j; z < zz; ++z)
{
add(a[z].x2+1,a[z].y2+1,-1);
add(a[z].x1,a[z].y1,-1);
add(a[z].x1,a[z].y2+1,1);
add(a[z].x2+1,a[z].y1,1);
}
for(auto it : q[i])
{
if(query(it.first, it.second))
{
ans++;
}
}
for(int z = j; z < zz; ++z)
{
add(a[z].x2+1,a[z].y2+1,1);
add(a[z].x1,a[z].y1,1);
add(a[z].x1,a[z].y2+1,-1);
add(a[z].x2+1,a[z].y1,-1);
}
j = zz;
}
printf("%d\n",ans);
return 0;
}