zoukankan      html  css  js  c++  java
  • 二维st表,一种暴力但却快速的二维RMQ利器

    先上例题:[HAOI2007]理想的正方形 大部分人都用单调队列,但我不会。首先我们可以暴力枚举所有的可能的正方形,每次我们需要查询RMQ,如果用朴素的方法总复杂度就会变成N^4,你不T谁T

    那怎么办,总不可能写正解吧,我们可以用二维st表,预处理N2logN,每次O(1)查询,N2水过。

    二维st表原理就是将一个正方形分成了4份:
    令 st[i][j][k]表示左上角为i,j,边长为k的正方形中的最大值。
    sta[i][j][k]=Max(sta[i][j][k-1],sta[i+(1<<k-1)][j][k-1],sta[i][j+(1<<k-1)][k-1],sta[i+(1<<k-1)][j+(1<<k-1)][k-1]);

    i,j,k-1:就是左上角那块正方形,i+(1<<k-1),j,k-1,就是左下角那块正方形,剩下两块就是另外两个
    查询同理,将代码放到编译器中食用更佳

    注意,强制类型转换要用大括号括起要转换的东西,例如 (int)(log(n)/log(2));

    Code:

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define zmd main
    int a,b,n;
    int sta[1026][1026][12],sti[1026][1026][12];
    int kk;
    inline int query1(int x,int y,int xx,int yy)
    {
    	int t1=sta[x][y][kk],t2=sta[xx-(1<<kk)+1][y][kk],t3=sta[x][yy-(1<<kk)+1][kk],t4=sta[xx-(1<<kk)+1][yy-(1<<kk)+1][kk];
    	return max(max(max(t1,t2),t3),t4);
    }
    inline int query2(int x,int y,int xx,int yy)
    {
    	int t1=sti[x][y][kk],t2=sti[xx-(1<<kk)+1][y][kk],t3=sti[x][yy-(1<<kk)+1][kk],t4=sti[xx-(1<<kk)+1][yy-(1<<kk)+1][kk];
    	return min(min(min(t1,t2),t3),t4);
    }
    inline int Max(int a,int b,int c,int d)
    {
    	return max(max(max(a,b),c),d);
    }
    inline int Min(int a,int b,int c,int d)
    {
    	return min(min(min(a,b),c),d);
    }
    int zmd()
    {
    	std::cin>>a>>b>>n;
    	for (int i=1;i<=a;++i) for (int j=1,tmp;j<=b;++j) {scanf("%d",&tmp);sta[i][j][0]=sti[i][j][0]=tmp;}
    	int shit=min(a,b);
    	for (int k=1;k<=11;++k)
    		for (int i=1;i+(1<<k)-1<=a;++i)
    			for (int j=1;j+(1<<k)-1<=b;++j)
    			{
    				sta[i][j][k]=Max(sta[i][j][k-1],sta[i+(1<<k-1)][j][k-1],sta[i][j+(1<<k-1)][k-1],sta[i+(1<<k-1)][j+(1<<k-1)][k-1]);
    				sti[i][j][k]=Min(sti[i][j][k-1],sti[i+(1<<k-1)][j][k-1],sti[i][j+(1<<k-1)][k-1],sti[i+(1<<k-1)][j+(1<<k-1)][k-1]);
    			}
    	kk=(int)(log(n)/log(2));
    	int ans=0x3f3f3f3f;
    	for (int i=1;i+n-1<=a;i++)
    	for (int j=1;j+n-1<=b;j++)
    		ans=std::min(ans,query1(i,j,i+n-1,j+n-1)-query2(i,j,i+n-1,j+n-1));
    	cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    js对象数组(JSON) 根据某个共同字段 分组
    一个 函数 用来转化esSearch 的range 条件
    关于 vuex 报错 Do not mutate vuex store state outside mutation handlers.
    android listview 重用view导致的选择混乱问题
    android SDK和ADT的更新
    Android中adb push和adb install的使用区别
    pycharm中添加扩展工具pylint
    su Authentication failure解决
    Putty以及adb网络调试
    有关android源码编译的几个问题
  • 原文地址:https://www.cnblogs.com/bullshit/p/9583359.html
Copyright © 2011-2022 走看看