Codeforces869 E. The Untended Antiquity (随机化算法)

题意:

有一个n*m的网格图,q次操作:
操作有三种:
1.将一个矩形区域加上围栏
2.将一个矩形区域的围栏拆掉
3.给定两个格子的坐标,问他们直接是否存在没有围栏的路

数据范围:n,m<=2500,q<=1e5

解法:
如果两个格子之存在没有围栏的路,那么包围他们的几层围栏一定完全相同
但是操作一共1e5,没办法记录每个格子被哪些围栏包围,时空复杂度都不够
一种办法是对围栏赋予一个随机数t,将矩形围起来等同于矩形内每个点都加上t
这样的话判断两个格子是否被相同围栏围住只需要判断两个格子的值是否相等即可
矩形赋值容易想到二维差分前缀和,因为需要动态维护,所以上二维树状数组
code:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=2500+5;
struct BIT{
    ull c[N][N];
    int lowbit(int i){
        return i&-i;
    }
    void add(int x,int y,ull t){
        for(int i=x;i<N;i+=lowbit(i)){
            for(int j=y;j<N;j+=lowbit(j)){
                c[i][j]+=t;
            }
        }
    }
    ull ask(int x,int y){
        ull ans=0;
        for(int i=x;i;i-=lowbit(i)){
            for(int j=y;j;j-=lowbit(j)){
                ans+=c[i][j];
            }
        }
        return ans;
    }
}T;
int n,m,q;
int seed1;
int seed2;
ull getrand(int x,int y,int xx,int yy){
    ull ans=x*seed1+y*seed2;
    ans=ans*seed1+ans*seed2+xx*seed1+yy*seed2;
    ans=ans*seed2+ans*seed1;
    return ans;
}
void cal(int x,int y,int xx,int yy,ull t){//二维差分
    T.add(x,y,t);T.add(xx+1,yy+1,t);
    T.add(x,yy+1,-t);T.add(xx+1,y,-t);
}
signed main(){
    seed1=rand();//随机数种子1
    seed2=rand();//随机数种子2
    scanf("%d%d%d",&n,&m,&q);
    while(q--){
        int op,x,y,xx,yy;
        x++,y++,xx++,yy++;
        scanf("%d%d%d%d%d",&op,&x,&y,&xx,&yy);
        if(op==1){//添加
            ull t=getrand(x,y,xx,yy);
            cal(x,y,xx,yy,t);
        }else if(op==2){//删除
            ull t=getrand(x,y,xx,yy);
            cal(x,y,xx,yy,-t);
        }else{//查询
            ull a=T.ask(x,y);
            ull b=T.ask(xx,yy);
            if(a==b)puts("Yes");
            else puts("No");
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值