zoukankan      html  css  js  c++  java
  • The UVALIVE 7716 二维区间第k小

    The UVALIVE 7716 二维区间第k小

     /**
    题意:给一个n * n的矩阵,有q个查询
          每次查询r,c,s,k表示已(r,c)为右上角 大小为s的正方形中 第k小的元素
         n <= 250 ,q <= 250000 , a[i][j]<=10000
          
    思路:用到了主席树求区间第k小,
          主席树本质是可持久化权值线段树,用区间[l,r]表示值在[l,r]间的数字有多少个
          每插入一个数字,实际上只修改了log个区间,其他的部分不发生变化,所以只需要对修改的区间新开结点即可
          求区间第k小,其实就是二分区间[l,r],m = l + r>>1
          如果权值[l,m]的数字个数少于k,那么答案就在[m+1,r]这个区间内
          否则就在[l,m]内,然后递归处理即可
          开始的做法是用以root[i][j]为根的树表示[1,1]到[i,j]的矩阵的信息,这样查询的复杂度为log(maxn)
          由于合并的复杂度不太科学,爆内存了
          然后改成以root[i][j]为根的树表示[i,1]到[i,j]区间的信息,空间复杂度为O(N * N * logN)
          然后我查询r,c,s,k的时候
          就把r行,r+1行,...r+s-1行的这些[c,c+s-1]区间一起操作,这样查询一次的复杂度为s * log(maxn)
    */
    
    #include<bits/stdc++.h>
    #define ls(i) seg[i].lc
    #define rs(i) seg[i].rc
    using namespace std;
    typedef long long LL;
    const int maxn = 1e4;
    const int N = 280;
    int n,q,rr,cc,ss,k;
    int b[N][2];
    struct node{
        int lc,rc,cnt;
    }seg[N * N * 100];
    int tot;
    int root[N][N];
    void update(int &rt,int l,int r,int pos,int val){
        seg[++tot] = seg[rt];
        rt = tot;
        seg[rt].cnt += val;
        if(l >= r) return ;
        int m = (l + r)>>1;
        if(pos <= m) update(ls(rt),l,m,pos,val);
        else update(rs(rt),m+1,r,pos,val);
    }
    int query(int l,int r,int k){
         if(l == r) return l;
         int m = (l + r)>>1;
         int cnt = 0;
         for(int i = 0;i < ss;i++) cnt += seg[ls(b[i][0])].cnt - seg[ls(b[i][1])].cnt;
         if(cnt < k) {
            for(int i = 0;i < ss;i++){
                 b[i][0] = rs(b[i][0]);
                 b[i][1] = rs(b[i][1]);
            }
            return  query(m+1,r,k - cnt);
         }
         for(int i = 0;i < ss;i++){
                 b[i][0] = ls(b[i][0]);
                 b[i][1] = ls(b[i][1]);
         }
         return  query(l,m,k);
    }
    int solve(){
       for(int i = 0;i < ss;i++){
            b[i][0] = root[rr + i][cc + ss - 1];
            b[i][1] = root[rr + i][cc - 1];
       }
       return query(1,maxn,k);
    }
    int main()
    {
        while(scanf("%d",&n)==1){
            tot = 0;
            for(int i = 1;i <= n;i++){
                for(int j = 1;j <= n;j++){
                    int x;
                    scanf("%d",&x);
                    root[i][j] = root[i][j-1];
                    update(root[i][j],1,maxn,x,1);
                }
            }
            scanf("%d",&q);
            while(q--){
                scanf("%d%d%d%d",&rr,&cc,&ss,&k);
                ss = min(ss,min(n - rr + 1,n - cc + 1));
                k = min(k , ss * ss);
                printf("%d
    ",solve());
            }
        }
        return 0;
    }
    
  • 相关阅读:
    HDNOIP普及+提高整合
    [BZOJ4016][FJOI2014]最短路径树问题
    [BZOJ3697]采药人的路径
    [COJ0985]WZJ的数据结构(负十五)
    [KOJ6024]合并果子·改(强化版)
    [KOJ6023]合并果子·改
    [KOJ0574NOIP200406合并果子]
    Atomic operations on the x86 processors
    Javascript 严格模式详解
    const C语言(转)
  • 原文地址:https://www.cnblogs.com/jiachinzhao/p/7265890.html
Copyright © 2011-2022 走看看