划分树几道题目

原创 2013年12月04日 14:04:18

主要参考kuangbin博客

个人感觉划分树是基于快速排序的分治的思想,是把快速排序每个过程记录下来而已(借助快速排序也是可以快速求整个区间第k值的)

对于每个区间,找中间值比较分成两个子区间,再递归处理

划分树Hdu4251(区间第k值)

typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> VI;
const int INF = 1000000000;
#define lson l, m, dep + 1
#define rson m + 1, r, dep + 1
const int maxn = 100010;
const int deep = 30;
 
int t[deep][maxn];
int st[maxn];
int toleft[deep][maxn];
 
void build(int l, int r, int dep)
{
   int i;
   if (l == r) return;
   int m = (r + l) >> 1;
   int same = m - l + 1;//表示等于中间值而且被分入左边的个数
   for (i = l; i <= r; i++)
       if (t[dep][i] < st[m])
           same--;
   int lpos = l;
   int rpos = m + 1;
   for (i = l; i <= r; i++)
    {
       if (t[dep][i] < st[m])//比中间的数小,分入左边
           t[dep + 1][lpos++] = t[dep][i];
       else if (t[dep][i] == st[m] && same > 0)
       {
           t[dep + 1][lpos++] = t[dep][i];
           same--;
       }
       else// if (t[dep][i] > st[m]) //比中间值大分入右边
            t[dep + 1][rpos++] = t[dep][i];
       toleft[dep][i] = toleft[dep][l - 1] + lpos - l;//从1到i放左边的个数
    }
   build(lson);
   build(rson);
}
 
//查询区间第k大的数,[l,r]是大区间,[L,R]是要查询的小区间
int query(int L, int R, int k,int l, int r,int dep)
{
   if (l == r) return t[dep][l];///!!!!!!!!!!!!!!!!!!!!!!!!!!!!1
   int m = (l + r) >> 1;
   int cnt = toleft[dep][R] - toleft[dep][L - 1];//[L,R]中位于左边的个数
   if (cnt >= k)
    {
       //l+要查询的区间前被放在左边的个数
       int newl = l + toleft[dep][L - 1] - toleft[dep][l - 1];
       //左端点加上查询区间会被放在左边的个数
       int newr = newl + cnt - 1;
       return query(newl, newr, k, lson);///!!!!!newl, newr
    }
   else
    {
       int newr = R + toleft[dep][r] - toleft[dep][R];
       int newl = newr - (R - L - cnt);
       return query(newl, newr, k - cnt, rson);///!!!!!!
    }
}
 
int main()
{
   int n, m;
   int a, b;
   int p = 1;
   while (cin >> n)
    {
       CLR(t, 0);///
       FE(i, 1, n)///
       {
           RI(t[0][i]);
           st[i] = t[0][i];
       }
       sort(st + 1, st + n + 1);///
       build(1, n, 0);///
       printf("Case %d:\n",p++);
       cin >> m;
       REP(i, m)
       {
           RII(a, b);
           printf("%d\n",query(a, b, (b - a) / 2 + 1, 1, n, 0));
       }
    }
}

划分树hdu 3473 (Minimum Sum )增加了一个lsum【】函数

typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> VI;
const int INF = 1000000000;
const int maxn = 100010;
const int deep = 20;
 
#define lson l, m, dep + 1
#define rson m + 1, r, dep + 1
 
int t[deep][maxn];
int toleft[deep][maxn];
int st[maxn];
LL lsum[deep][maxn];
//LL sum[maxn];
LL ans;
 
void build(int l, int r, int dep)
{
   if (l == r) {
       lsum[dep][l] = t[dep][l];
       return ;
    }
   int m = (l + r) >> 1;
   int same = m - l + 1;
   FE(i, l, r)
    {
       if (t[dep][i] < st[m])
           same--;
       lsum[dep][i] = t[dep][i];
       if (i != l) lsum[dep][i] += lsum[dep][i - 1];
    }
   int lpos = l;
   int rpos = m + 1;
   FE(i, l, r)
    {
       if (t[dep][i] < st[m])
           t[dep + 1][lpos++] = t[dep][i];
       else if (t[dep][i] == st[m] && same > 0)
       {
           t[dep + 1][lpos++] = t[dep][i];
           same--;
       }
       else
           t[dep + 1][rpos++] = t[dep][i];
       toleft[dep][i] = toleft[dep][l - 1] + lpos - l;///
    }
   build(lson);
   build(rson);
}
 
int query(int L,int R, int k, int l, int r,int dep)
{
   if (L == R ) return t[dep][L];
   int cnt = toleft[dep][R] - toleft[dep][L - 1];
   int m = (l + r) >> 1;
 
   int ln1 = toleft[dep][L - 1] - toleft[dep][l - 1];
   int rn1 = L - l - ln1;
 
   int ln2 = cnt;
   int rn2 = R - L + 1 - cnt;
 
   if (cnt >= k)
    {
       if (rn2 > 0)
       {
           if (rn1 > 0)
                ans += lsum[dep + 1][m + rn1 +rn2] - lsum[dep + 1][m + rn1];///@@@@///dep + 1
           else ans += lsum[dep + 1][m + rn2];
       }
 
       int newl = l + ln1;
       int newr = newl + cnt - 1;
       return query(newl, newr, k, lson);
    }
   else
    {
       if (ln2 > 0)
       {
           if (ln1 > 0)
                ans -= lsum[dep + 1][l - 1 +ln1 + ln2] - lsum[dep + 1][l - 1 + ln1];
           else ans -= lsum[dep + 1][l - 1 + ln2];
       }
 
       int newr = R + toleft[dep][r] - toleft[dep][R];
       int newl = newr - (R - L - cnt);
       return query(newl, newr, k - cnt, rson);
    }
 
}
 
int T;
int n, m;
int main()
{
   int x, y;
   cin >> T;
   int p = 1;
   while (T--)
    {
       RI(n);
//       CLR(t, 0,);///
//       CLR(toleft, 0);///
       FE(i, 1, n)
       {
           RI(t[0][i]);
           st[i] = t[0][i];
       }
       sort(st + 1, st + n + 1);
       build(1, n, 0);///
       printf("Case #%d:\n",p++);
       RI(m);
       REP(i, m)
       {
           RII(x, y);
           x++;
           y++;
           ans = 0;
           LL midval = query(x, y, (y - x) / 2 + 1, 1, n, 0);///0
           if ((y - x + 1) % 2 == 0) ans -= midval;
           cout << ans << endl;
       }
       printf("\n");
    }
}
 
又一解法主要是lsum的处理不同

const int MAXN = 100010;
const int MOD = 1000000;

#define lson l, m, dep + 1
#define rson m + 1, r, dep + 1
int t[20][MAXN];
int st[MAXN];
int tol[20][MAXN];
LL lsum[20][MAXN];
LL ans;
int n, m;

void build(int l, int r, int dep)
{
    if (l == r)
    {
        return ;
    }
    int m = (l + r) >> 1;
    int same = (m - l + 1);
    FE(i, l, r) if (st[m] > t[dep][i]) same--;
    int lpos = l;
    int rpos = m + 1;
    FE(i, l, r)
    {
        if (t[dep][i] < st[m]) t[dep + 1][lpos++] = t[dep][i];
        else if (t[dep][i] == st[m] && same > 0) t[dep + 1][lpos++] = t[dep][i], same--;
        else t[dep + 1][rpos++] = t[dep][i];
        tol[dep][i] = tol[dep][l - 1] + lpos - l;
    }
    FE(i, l, r) lsum[dep + 1][i] = lsum[dep + 1][i - 1] + t[dep + 1][i];
    build(lson);
    build(rson);
}

LL query(int L, int R, int k, int l, int r, int dep)
{
    if (L == R) return t[dep][L];
    int m = (r + l) >> 1;
    int cnt = tol[dep][R] - tol[dep][L - 1];

    int ln1 = tol[dep][L - 1] - tol[dep][l - 1];
    int rn1 = L - l - ln1;

    int ln2 = cnt;
    int rn2 = R - L - cnt + 1;

    if (cnt >= k)//toleft
    {
        if (rn2 > 0) ans += lsum[dep + 1][m + rn2 + rn1] - lsum[dep + 1][m + rn1];
        int newl = l + tol[dep][L - 1] - tol[dep][l - 1];
        int newr = newl + cnt - 1;
        query(newl, newr, k, lson);
    }
    else//toright
    {
        if (ln2 > 0) ans -= lsum[dep + 1][l + ln2 + ln1 - 1] - lsum[dep + 1][l + ln1 - 1];
        int newr = R + tol[dep][r] - tol[dep][R];
        int newl = newr - (R - L - cnt);
        query(newl, newr, k - cnt, rson);
    }
}

int main()
{
    int T;
    RI(T);
    int x, y;
    int ncase = 1;
    while (T--)
    {

        RI(n);
        CLR(t, 0);
        CLR(lsum, 0);
        CLR(tol, 0);
        FE(i, 1, n)
        {
            RI(st[i]);
            t[0][i] = lsum[0][i] = st[i];
        }
        sort(st + 1, st + n + 1);
        FE(i, 1, n) lsum[0][i] += lsum[0][i - 1];
        build(1, n, 0);
        RI(m);        
        printf("Case #%d:\n", ncase++);
        while (m--)
        {
            RII(x, y);
            x++;
            y++;
            ans = 0;
            int mid = query(x, y, (y - x) / 2 + 1, 1, n, 0);
            if ((y - x + 1) % 2 == 0) ans -= mid;
            cout << ans << endl;
        }
        cout << endl;
    }
}


划分树hdu 4417SuperMario (求给定数在给定区间的中比它小的数的个数,或大小位置)(求逆序数)(通过修改query)(也可以二分答案!!!!!!!!!!!)

typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> VI;
const int INF = 1000000000;
const int maxn = 100010;
const int deep = 20;
 
#define lson l, m, dep + 1
#define rson m + 1, r, dep + 1
 
int t[deep][maxn];
int tol[deep][maxn];
int st[maxn];
int n;
void build(int l, int r, int dep)
{
   if (l == r) return;
   int m = (l + r) >> 1;
   int same = m - l + 1;
   FE(i, l, r)
       if (t[dep][i] < st[m]) same--;
   int lpos = l;
   int rpos = m + 1;
   FE(i, l, r)
    {
       if (t[dep][i] < st[m]) t[dep + 1][lpos++] = t[dep][i];
       else if (t[dep][i] == st[m] && same > 0) { t[dep + 1][lpos++]=  t[dep][i]; same--; }
       else t[dep + 1][rpos++] = t[dep][i];
       tol[dep][i] = tol[dep][l - 1] + lpos - l;
    }
   build(lson);
   build(rson);
}
 
int ans;
int h;
void query(int L, int R, int l, int r, intdep)
{
   if (L == R)
    {
       if (t[dep][L] <= h)
           ans++;
       return ;
    }
   int m = (l + r) >> 1;
   int cnt = tol[dep][R] - tol[dep][L - 1];
 
//   int ln1 = tol[dep][L - 1] - tol[dep][l - 1];
//   int rn1 = L - l - ln1;
//
//   int ln2 = cnt;
//   int rn2 = R - L - cnt + 1;
//
//   int lr = t[dep + 1][l - 1 + ln1 + ln2];
//   int rl = t[dep + 1][m + rn1 + 1];
 
   if (st[m] > h)
    {
       int newl = l + tol[dep][L - 1] - tol[dep][l - 1];
       int newr = newl + cnt - 1;
       if (newl <= newr)///?!!!!!!!!!!!
       query(newl, newr, lson);
    }
    else
    {
       ans += cnt;
       int newr = R + tol[dep][r] - tol[dep][R];
       int newl = newr - (R - L - cnt);
       if (newl <= newr)///?!!!!!!!!!!!
       query(newl, newr, rson);
    }
}
 
int T;
 
int main()
{
   int x, y, z;
   int T;
   int p = 1;
   RI(T);
   while (T--)
    {
       //初始化
       printf("Case %d:\n",p++);
       CLR(t, 0);
       CLR(tol, 0);
       int m;
       RII(n, m);
       FE(i, 1, n)///
       {
           RI(t[0][i]);
           st[i] = t[0][i];
       }
       sort(st + 1, st + n + 1);
       build(1, n, 0);
 
       while (m--)
       {
           RIII(x, y, z);
           h = z;
           ans = 0;
           query(++x, ++y, 1, n, 0);
           cout << ans << endl;
       }
    }
}

划分树算法 模板

转:http://www.cnblogs.com/pony1993/archive/2012/07/17/2594544.html划分树是一种基于线段树的数据结构。主要用于快速求出(在log(n)的时...
  • Littlewhite520
  • Littlewhite520
  • 2017-04-20 00:22:20
  • 335

HDU 2665 Kth number 划分树

题目:http://acm.hdu.edu.cn/showproblem.php?pid=2665 题意:求给定区间中的第k大值 思路:划分树模板题 #include #inc...
  • discreeter
  • discreeter
  • 2016-05-17 14:21:03
  • 393

区间第K大数——划分树(POJ2104解题报告)

百度百科:划分树是一种基于线段树的数据结构。主要用于快速求出(在log(n)的时间复杂度内)序列区间的第k大值。 划分树的基本思想就是对于某个区间,把它划分成两个子区间,左边区间的数小于右边区间的数...
  • Acceptedxukai
  • Acceptedxukai
  • 2011-11-04 21:05:58
  • 4501

poj 2104 K-th Number - 经典划分树

Description You are working for Macrohard company in data structures department. After failing yo...
  • u012183589
  • u012183589
  • 2015-07-08 18:40:05
  • 606

数据结构----划分树

今晚又学了另外一种树----划分树。看了一晚上了,也是大概明白一些而已,对于一些细节还是不太理解。 划分树是一种基于线段树的数据结构。主要用于快速求出(在log(n)的时间复杂度内)序列区间的第k...
  • Lin_disguiser
  • Lin_disguiser
  • 2016-08-02 00:34:11
  • 1174

划分树成熟模板(可解决相同元素)+二分

HDOJ 4417 - Super Mario 划分树成熟模板(可解决相同元素)+二分   POJ 2104 - K-th Number 划分树初步(不能有...
  • pi9nc
  • pi9nc
  • 2013-09-20 14:58:49
  • 905

POJ 2104 - K-th Number 划分树初步(不能有相同元素)

划分树的模型是用来解决一类求一列数的某个区间第k小数的问题.当然也可以通过二分来球一个数在某区间里是第几小...跟我的感觉划分树和线段树很多地方挺相似的..       1、划分树的构造       ...
  • kk303
  • kk303
  • 2013-08-07 19:25:21
  • 993

第四届蓝桥杯C/C++本科B组第二道大题

太困了就睡了觉,还有20分钟的时候醒了去了趟cs(厕所),回来后推 了出来。。。最后的6分钟前三分钟纠结要不要写、后三分钟写完没有运行直 接提交,无悬念wa囧~;今儿个随便参加了场比赛竟然有此题原...
  • Ice_Crazy
  • Ice_Crazy
  • 2013-07-19 18:29:56
  • 1359

const

在C++程序中,经常用const 来限制对一个对象的操作,例如,将一个变量定义为const 的:  const  int  n=3; 则这个变量的值不能被修改,即不能对变量赋值。        ...
  • zp___waj
  • zp___waj
  • 2015-04-03 19:53:56
  • 244

什么是脏读,不可重复读,幻读

1.脏读:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。 2.不可重复读:是指在一个事务内,多次读同一...
  • u011686226
  • u011686226
  • 2016-08-23 11:36:33
  • 225
收藏助手
不良信息举报
您举报文章:划分树几道题目
举报原因:
原因补充:

(最多只允许输入30个字)