1. 程式人生 > >2018牛客暑期多校第二場J(二維陣列陣列+hash)

2018牛客暑期多校第二場J(二維陣列陣列+hash)

題面:farm

White Rabbit has a rectangular farmland of n*m. In each of the grid there is a kind of plant. The plant in the j-th column of the i-th row belongs the a[i][j]-th type.
White Cloud wants to help White Rabbit fertilize plants, but the i-th plant can only adapt to the i-th fertilizer. If the j-th fertilizer is applied to the i-th plant (i!=j), the plant will immediately die.
Now White Cloud plans to apply fertilizers T times. In the i-th plan, White Cloud will use k[i]-th fertilizer to fertilize all the plants in a rectangle [x1[i]...x2[i]][y1[i]...y2[i]].
White rabbits wants to know how many plants would eventually die if they were to be fertilized according to the expected schedule of White Cloud.

輸入描述:

The first line of input contains 3 integers n,m,T(n*m<=1000000,T<=1000000)
For the next n lines, each line contains m integers in range[1,n*m] denoting the type of plant in each grid.
For the next T lines, the i-th line contains 5 integers x1,y1,x2,y2,k(1<=x1<=x2<=n,1<=y1<=y2<=m,1<=k<=n*m)

輸出描述:

Print an integer, denoting the number of plants which would die.

輸入

2 2 2
1 2
2 3
1 1 2 2 2
2 1 2 1 1

輸出

3

題目描述:

給出一個n*m(n*m<=1000000)的農場,以及每個格子中植物的種類編號∈[1,n*m],

接著給出T(T<=1000000)次施肥的資訊,資訊包括x1,y1,x2,y2,k(1<=x1<=x2<=n,1<=y1<=y2<=m,1<=k<=n*m)

表示給在座標(x1,y1)到座標(x2,y2)的區間中全部植物施加編號為k的肥料。

已知植物被不同於自身編號的肥料施加後會死去,問全部施肥操作後有多少株植物會死去。

題目分析:

初始條件:首先將全部施肥操作區域+1加入到二維樹狀陣列中

按植物種類進行處理,對於第 k 種植物死亡數的統計過程如下:

①將全部施加編號為k的肥料的操作撤回,也就是將編號為k 的施肥區域全部-1。

②查詢所有編號為k的植物的格子被施加了多少次肥料,如果不為0則該植物死亡,統計答案ans++(因為如果還有肥料的話,這些肥料已經不是編號為k的了);

③將全部施加編號為k的肥料的操作回覆,也就是將編號為k 的施肥區域全部+1。

④若k<n*m,k=k+1,回到①。

另外本文寫的做法是隨機hash:

①先給每個編號一個隨機的hash值(記為_rand[ ])。

②給區域施加編號為k的化肥的操作,是讓該區域全部加上編號k對應的hash值_rand[k]。

③擁有編號k植物的格子,如果查詢到的值是_rand[k]的倍數,那麼說明這個格子只有第k種化肥施加過,如果不是_rand[k]的倍數(說明存在其他肥料),那麼該植物死亡,統計答案ans++

以下是該做法的程式碼

程式碼:

#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<string>
#include<math.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#define INF 0x3f3f3f3f//3f3f3f3f
#define ll long long
#define ull unsigned long long
const long long MOD = 1000000007;
#define lowbit(a) ((a)&(-(a)))
using namespace std;
int n, m, t;
int _rand[1000005];
vector<ll>bit[1000005];//需要開ll,因為hash值加和之後會爆int
vector<int>a[1000005];
//二維bit陣列單點修改
void add(int x,int y,int k){
    for(int i=x;i<=n;i+=lowbit(i))
        for(int j=y;j<=m;j+=lowbit(j))
            bit[i][j]+=k;
}
//二維bit陣列區域修改
void update(int x,int y,int _x,int _y,int k){
    add(x,y,k);
    add(_x+1,_y+1,k);
    add(x,_y+1,-k);
    add(_x+1,y,-k);
}
//二維bit陣列單點查詢
ll query(int x,int y){
    ll res=0;
    for(int i=x;i;i-=lowbit(i))
        for(int j=y;j;j-=lowbit(j))
            res+=bit[i][j];
    return res;
}
int main(){
    int x,y,_x,_y,k;
    for(int i=1;i<=1000000;i++)//瞎jr隨機,hash值
        _rand[i]=abs(rand()*13131+17)%100000000+13131;//取模數的大小決定了hash值的範圍,這個範圍過小會發生碰撞
    while(~scanf("%d %d %d",&n,&m,&t)){
        for(int i=1;i<=n;i++){//給vector分配大小
            bit[i].resize(m+2);a[i].resize(m+2);
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%d",&x);
                a[i][j]=x;
            }
        }
        for(int i=1;i<=t;i++){
            scanf("%d %d %d %d %d",&x,&y,&_x,&_y,&k);
            update(x,y,_x,_y,_rand[k]);//區域更新
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(query(i,j)%_rand[a[i][j]]!=0)ans++;
            }
        }
        printf("%d\n",ans);
    }
}