1. 程式人生 > >Codeforces 869E. The Untended Antiquity (二維Fenwick,Hash)

Codeforces 869E. The Untended Antiquity (二維Fenwick,Hash)

Codeforces 869E. The Untended Antiquity

題意:

在一張mxn的格子紙上,進行q次操作:
1,指定一個矩形將它用柵欄圍起來。
2,撤掉一個已有的柵欄。
3,詢問指定兩點之間是否連通(即能否從其中一點不翻越柵欄走到另一點)

思路:

對於操作1,將給定的矩形雜湊成一個數(可對點座標進行進位制雜湊),對整個矩形所覆蓋的點都累加上這個數;
對於操作2,則逆著把操作1的影響抵消掉;
對於操作3,看一下兩點的值是否相同(相同表示他們被相同的矩形們所覆蓋)。
至於每次矩形內的所有點的修改操作以及單點查值,使用二維樹狀陣列來維護,用到了差分思想,維護的是差分陣列,則單點查詢即求差分陣列的字首和。具體可見程式碼,在圖上畫一畫,不難理解

程式碼:

#include<bits/stdc++.h>
#define de(x) cout<<#x<<" = "<<x<<"\n"
#define dd(x) cout<<#x<<" = "<<x<<" "
#define sz(x) int(x.size())
#define All(x) x.begin(),x.end()
#define fi first
#define se second
#define pb push_back
#define mp make_pair
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> P;
typedef priority_queue<int> BQ;
typedef priority_queue<int,vector<int>,greater<int> > SQ;
const int maxn=3e3+10,INF=0x3f3f3f3f;
ll fw[maxn][maxn];
void add(int x,int y,ll c)
{
    for (int i=x;i<maxn;i+=i&-i)
        for (int j=y;j<maxn;j+=j&-j)
            fw[i][j]+=c;
}
ll qry(int x,int y)
{
    ll res=0;
    for (int i=x;i;i-=i&-i)
        for (int j=y;j;j-=j&-j)
            res+=fw[i][j];
    return res;
}
ll seed=2333;
inline ll Hash(int a,int b,int c,int d)
{
    return a*seed*seed*seed+b*seed*seed+c*seed+d;
}
int main()
{
    int n,m,q;
    cin>>n>>m>>q;
    for (int i=0;i<q;++i)
    {
        int op,x1,y1,x2,y2;
        scanf("%d%d%d%d%d",&op,&x1,&y1,&x2,&y2);
        if (op==3)
        {
            if (qry(x1,y1)==qry(x2,y2))
                printf("Yes\n");
            else
                printf("No\n");
        }
        else
        {
            ll hs=Hash(x1,y1,x2,y2);
            if (op==2)
                hs=-hs;
            add(x1,y1,hs);
            add(x2+1,y2+1,hs);
            add(x1,y2+1,-hs);
            add(x2+1,y1,-hs);
        }
    }
    return 0;
}