hdu3473 线段树 划分树

  1 //Accepted    28904 KB    781 ms
  2 //划分树
  3 //所求x即为l,r区间排序后的中位数t
  4 //然后求出小于t的数的和sum1,这个可以用划分树做
  5 //求出整个区间的和sum,可以用O(1)的数组做
  6 //ans=(k-1)*t-sum1+sum-sum1-(l-r+1-k+1)*t
  7 #include <cstdio>
  8 #include <cstring>
  9 #include <iostream>
 10 #include <queue>
 11 #include <cmath>
 12 #include <algorithm>
 13 using namespace std;
 14 /**
 15   * This is a documentation comment block
 16   * 如果有一天你坚持不下去了,就想想你为什么走到这儿!
 17   * @authr songt
 18   */
 19 const int imax_n = 100005;
 20 struct node
 21 {
 22     int val[imax_n];
 23     int num[imax_n];
 24     __int64 sum[imax_n];
 25 }f[20];
 26
 27 int a[imax_n];
 28 __int64 all[imax_n];
 29 int sorted[imax_n];
 30 int n;
 31
 32 void build(int t,int l,int r)
 33 {
 34     if (l==r) return ;
 35     int mid=(l+r)/2;
 36     int isame=mid-l+1;
 37     int same=0;
 38     for (int i=l;i<=r;i++)
 39     {
 40         if (f[t].val[i]<sorted[mid]) isame--;
 41     }
 42     int ln=l;
 43     int rn=mid+1;
 44     for (int i=l;i<=r;i++)
 45     {
 46         if (i==l)
 47         {
 48             f[t].num[i]=0;
 49             f[t].sum[i]=0;
 50         }
 51         else
 52         {
 53             f[t].sum[i]=f[t].sum[i-1];
 54             f[t].num[i]=f[t].num[i-1];
 55         }
 56
 57         if (f[t].val[i]<sorted[mid])
 58         {
 59             f[t].num[i]++;
 60             f[t].sum[i]+=f[t].val[i];
 61             f[t+1].val[ln++]=f[t].val[i];
 62         }
 63         else if (f[t].val[i]>sorted[mid])
 64         {
 65             f[t+1].val[rn++]=f[t].val[i];
 66         }
 67         else
 68         {
 69             if (same<isame)
 70             {
 71                 same++;
 72                 f[t].num[i]++;
 73                 f[t].sum[i]+=f[t].val[i];
 74                 f[t+1].val[ln++]=f[t].val[i];
 75             }
 76             else
 77             {
 78                 f[t+1].val[rn++]=f[t].val[i];
 79             }
 80         }
 81     }
 82     build(t+1,l,mid);
 83     build(t+1,mid+1,r);
 84 }
 85 __int64 sum=0;
 86 int lnum;
 87 int query(int t,int l,int r,int a,int b,int k)
 88 {
 89     int s,ss;
 90     if (l==r) return f[t].val[l];
 91     int mid=(l+r)/2;
 92     __int64 tsum=0;
 93     if (a==l)
 94     {
 95         ss=0;
 96         s=f[t].num[b];
 97         tsum=f[t].sum[b];
 98     }
 99     else
100     {
101         ss=f[t].num[a-1];
102         s=f[t].num[b]-ss;
103         tsum=f[t].sum[b]-f[t].sum[a-1];
104     }
105     if (s>=k)
106     {
107         a=l+ss;
108         b=l+ss+s-1;
109         return query(t+1,l,mid,a,b,k);
110     }
111     else
112     {
113         //lnum+=s;
114         int b1=a-l-ss;
115         int b2=b-a+1-s;
116         a=mid+1+b1;
117         b=mid+b1+b2;
118         sum+=tsum;
119         return query(t+1,mid+1,r,a,b,k-s);
120     }
121 }
122 int Q;
123 int x,y;
124 void slove()
125 {
126     build(0,1,n);
127     scanf("%d",&Q);
128     for (int i=1;i<=Q;i++)
129     {
130         scanf("%d%d",&x,&y);
131         x++;
132         y++;
133         __int64 sum1=all[y]-all[x-1];
134         //printf("sum1=%I64d\n",sum1);
135         sum=0;
136         //lnum=0;
137         //printf("sum=%I64d\n",sum);
138         int k=(x+y)/2-x+1;
139         int t=query(0,1,n,x,y,k);
140         //printf("t=%d\n",t);
141         lnum=k-1;
142         __int64 ans=-sum+sum1-sum-(__int64 )(y-x+1-lnum-lnum)*t;
143         printf("%I64d\n",ans);
144     }
145 }
146 int main()
147 {
148     int T;
149     int t=0;
150     scanf("%d",&T);
151     while (T--)
152     {
153         scanf("%d",&n);
154         all[0]=0;
155         for (int i=1;i<=n;i++)
156         {
157             scanf("%d",&a[i]);
158             f[0].val[i]=sorted[i]=a[i];
159             all[i]=all[i-1]+a[i];
160         }
161         printf("Case #%d:\n",++t);
162         sort(sorted+1,sorted+n+1);
163         slove();
164         printf("\n");
165     }
166     return 0;
167 }

时间: 2024-12-28 15:55:04

hdu3473 线段树 划分树的相关文章

归并树 划分树 可持久化线段树(主席树) 入门题 hdu 2665

如果题目给出1e5的数据范围,,以前只会用n*log(n)的方法去想 今天学了一下两三种n*n*log(n)的数据结构 他们就是大名鼎鼎的 归并树 划分树 主席树,,,, 首先来说两个问题,,区间第k大 ,,,, 这个问题的通用算法是 划分树,, 说白一点就是把快速排序的中间结果存起来, 举个栗子 原数列 4 1 8 2 6 9 5 3 7 sorted 1 2 3 4 5 6 7 8 9 ........................... qs[0] 4 1 8 2 6 9 5 3 7 q

划分树基础知识

原网址:划分树详解 对4 5 2 8 7 6 1 3 分别建划分树和归并树 划分树如下图 红色的点是此节点中被划分到左子树的点. 我们一般用一个结构体数组来保存每个节点,和线段树不同的是,线段树每个节点值保存一段的起始位置和结束位置,而在划分树和递归树中,每个节点的每个元素都是要保存的.为了直观些,我们可以定义一个结构体数组,一个结构体中保存的是一层的元素和到某个节点进入左子树的元素的个数,不同于线段树,我们不能保存一个节点的起始结尾位置,因为随层数的增加,虽然每个结构体保存的元素数目是一定的,

hdu 2665 Kth number(划分树)

题意:给定一列数,每次查询区间[s,t]中的第k大: 参考:http://www.cnblogs.com/kane0526/archive/2013/04/20/3033212.html http://www.cnblogs.com/kuangbin/archive/2012/08/14/2638829.html 思路:快排思想+线段树=划分树,也就是树的每一层都按规则划分: 对于本题,建树前,保存原数列排序后的数列,原数列作为树的顶层: 建树时,考虑当前区间中的中间值,若大于中间值,在下一层中

HDU 4417 Super Mario ( 超级马里奥 + 主席树 + 线段树/树状数组离线处理 + 划分树 )

HDU 4417 - Super Mario ( 主席树 + 线段树/树状数组离线处理 + 划分树 ) 这道题有很多种做法,我先学习的是主席树.后面陆续补上线段树离线和划分树 题目大意就是给定一个区间给定一个数列,每次要求你查询区间[L,R]内不超过K的数的数量 主席树做法: 最基本的是静态第k大,这里是求静态的 <= K,差不多,在Query操作里面需要修改修改 先建立size棵主席树,然后询问的时候统计的是 第R棵主席树中[1,K]的数量 - 第L-1棵主席树中[1,K]的数量 注意这里下标

划分树 poj2104 hdu5249

KPI Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 616    Accepted Submission(s): 261 Problem Description 你工作以后, KPI 就是你的所有了. 我开发了一个服务.取得了非常大的知名度.数十亿的请求被推到一个大管道后同一时候服务从管头拉取请求.让我们来定义每一个请求都有一个重要

POJ 2104 K-th Number(区间第k大数)(平方分割,归并树,划分树)

题目链接: http://poj.org/problem?id=2104 解题思路: 因为查询的个数m很大,朴素的求法无法在规定时间内求解.因此应该选用合理的方式维护数据来做到高效地查询. 如果x是第k个数,那么一定有 (1)在区间中不超过x的数不少于k个 (2)在区间中小于x的数有不到k个 因此,如果可以快速求出区间里不超过x的数的个数,就可以通过对x进行二分搜索来求出第k个数是多少. 接下来,我们来看一下如何计算在某个区间里不超过x个数的个数.如果不进行预处理,那么就只能遍历一遍所有元素.

POJ2104-K-th Number-求区间第K大数(暴力or归并树or划分树)

题目链接:http://poj.org/problem?id=2104 题目意思很简单,就是给你一个序列,查询某区间第K大的数: 方法1:时间复杂度O(N*M):不支持更新操作,代码简单: 利用结构体排序,保留原数据的顺序. #include <stdio.h> #include <iostream> #include <algorithm> #define N 100000 using namespace std; /* 这个思路很好:时间复杂度O(n*m): 不过还

HDU 4417 (划分树+区间小于k统计)

题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4417 题目大意:给定一个区间,以及一个k值,求该区间内小于等于k值的数的个数.注意区间是从0开始的. 解题思路: 首先这题线段树可以解.方法是维护一个区间最大值max,一个区间点个数s,如果k>max,则ans=s+Q(rson),否则ans=Q(lson). 然后也可以用求区间第K大的划分树来解决,在对原来求第K大的基础上改改就行,方法如下: Build方法同第K大. 对于Query: ①左区

POJ 2104 K-th Number(区间第k大数)(平方切割,归并树,划分树)

题目链接: http://poj.org/problem? id=2104 解题思路: 由于查询的个数m非常大.朴素的求法无法在规定时间内求解. 因此应该选用合理的方式维护数据来做到高效地查询. 假设x是第k个数,那么一定有 (1)在区间中不超过x的数不少于k个 (2)在区间中小于x的数有不到k个 因此.假设能够高速求出区间里不超过x的数的个数.就能够通过对x进行二分搜索来求出第k个数是多少. 接下来,我们来看一下怎样计算在某个区间里不超过x个数的个数. 假设不进行预处理,那么就仅仅能遍历一遍全