热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

BZOJ3295动态逆序对树套树,树状数组套线段树(主席树)

Orz黄学长,蒟蒻在黄学长的带领下,通过阅读黄学长的代码!终于会了这道题!首先我想先说一下这道题的思路(准确来说是黄学长的)。很明显,树状数组应该不用讲吧!关键是内存怎么开,维护一

    Orz黄学长,蒟蒻在黄学长的带领下,通过阅读黄学长的代码!终于会了这道题! 首先我想先说一下这道题的思路(准确来说是黄学长的)。 很明显,树状数组应该不用讲吧!关键是内存怎么开,维护一些什么样的数据? 其实我们通过观察,很快可以发现,你维护被删的数比维护所有的数轻松多了(不管是空间上,还是时间上)。所以我们就可以从这方面想!(其实我一开始的思路,因为这道题我已经看过很久了,一直想写,毕竟是白书里面的一道例题嘛!一开始,蒟蒻的我是打算这样的用树状数组套权值线段树,并且是维护所有的数,我发现空间不够我开的(或许是我太弱,有大神的话请指教一下。)。好像是因为我维护所有的数才错了,(而且就算要维护,也是动态开点第维护)仔细一想黄学长就是树状数组套权值线段树啊!太弱了我啊!too young too simple 。而且宝宝,开点的时候,一开始只开了一百万,WA掉了,后来看了黄学长开了五百万,自己再仔细一想,logN = 17 , 因为是树套树所以是 logN的平方, 还要乘上操作的次数M, 所以………………,我又错了。加油了多积累经验)。

这是黄学长的树状数组套权值线段树(当然,为了不当简单的做一条源程狗,我自己敲了一遍,并做了修改)

  1 #include
  2 #include
  3 #include
  4 #define rep(i,j,k) for(int i = j; i <= k; i++)
  5 #define down(i,j,k) for(int i = j; i >= k; i--)
  6 #define lc c[k][0]
  7 #define rc c[k][1]
  8 #define N 5000005
  9 #define ll long long
 10 #define maxn 102333
 11 using namespace std;
 12 
 13 int t[maxn], c[N][2], root[maxn], sum[N], a1[maxn], a2[maxn], pos[maxn], num[maxn];  
 14 int A[30], B[30]; 
 15 
 16 int cnt = 0, n, m;
 17 int read()
 18 {
 19     int s = 0, t = 1; char c = getchar();
 20     while( !isdigit(c) ){
 21         if( c == - ) t = -1; c = getchar();
 22     }
 23     while( isdigit(c) ){
 24         s = s * 10 + c - 0; c = getchar();
 25     }
 26     return s * t;
 27 }
 28 int lower(int x) {return x & (-x); }
 29 
 30 int get_num(int x)
 31 {
 32     int ans = 0;
 33     for( ; x; x -= lower(x))  ans += t[x];
 34     return ans;
 35 }
 36 
 37 void update(int&k,int l,int r,int num)
 38 {
 39     if( !k ) k = ++cnt;
 40     sum[k]++;
 41     if( l == r ) return;
 42     int mid = (l+r)>>1;
 43     if( mid 1,r,num);
 44     else update(lc,l,mid,num); 
 45 }
 46 
 47 ll get_more(int x,int y,int num)
 48 {
 49     A[0] = B[0] = 0; x--; ll tmp = 0;
 50     for( ; x; x -= lower(x) ) A[++A[0]] = root[x];
 51     for( ; y; y -= lower(y) ) B[++B[0]] = root[y];
 52     int l = 1, r = n;
 53     while( l != r ){
 54         int mid = (l+r)>>1;
 55         if( num <= mid ) {
 56             rep(i,1,A[0]) tmp -= sum[c[A[i]][1]];
 57             rep(i,1,B[0]) tmp += sum[c[B[i]][1]];
 58             rep(i,1,A[0]) A[i] = c[A[i]][0];
 59             rep(i,1,B[0]) B[i] = c[B[i]][0];
 60             r = mid;
 61         }
 62         else {
 63             rep(i,1,A[0]) A[i] = c[A[i]][1];
 64             rep(i,1,B[0]) B[i] = c[B[i]][1];
 65             l = mid+1;
 66         }
 67     }
 68     return tmp;
 69 }
 70 
 71 ll get_less(int x,int y,int num)
 72 {
 73     A[0] = B[0] = 0; x--; ll tmp = 0;
 74     for( ; x; x -= lower(x)) A[++A[0]] = root[x];
 75     for( ; y; y -= lower(y)) B[++B[0]] = root[y];
 76     int l = 1, r = n;
 77     while( l != r ){
 78         int mid = (l+r)>>1;
 79         if( num > mid ){
 80             rep(i,1,A[0]) tmp -= sum[c[A[i]][0]];
 81             rep(i,1,B[0]) tmp += sum[c[B[i]][0]];
 82             rep(i,1,A[0]) A[i] = c[A[i]][1];
 83             rep(i,1,B[0]) B[i] = c[B[i]][1];
 84             l = mid + 1;
 85         }
 86         else {
 87             rep(i,1,A[0]) A[i] = c[A[i]][0];
 88             rep(i,1,B[0]) B[i] = c[B[i]][0];
 89             r = mid;
 90         }
 91     }
 92     return tmp;
 93 }
 94 
 95 int main()
 96 {
 97     n = read(), m = read(); ll ans = 0;
 98     rep(i,1,n){
 99         num[i] = read(); pos[num[i]] = i;   
100         a1[i] = get_num(n)-get_num(num[i]-1);
101         ans += a1[i];
102         for(int x = num[i]; x <= n; x += lower(x) ) t[x]++;
103     }
104     memset(t,0,sizeof(t));
105     down(i,n,1){
106         int x = num[i];
107         a2[i] = get_num(x-1);
108         for( ; x <= n; x += lower(x) ) t[x]++;
109     }
110     rep(i,1,m){
111         printf("%lld\n", ans);
112         int x = read(); int po = pos[x];
113         ans -= (a1[po] + a2[po] - get_more(1,po-1,x) - get_less(po+1,n,x));
114         for( ; po <= n; po += lower(po) ) update(root[po],1,n,x);
115     } 
116     return 0;
117 }

据翻博客,有人分块A掉了,我不信,怎么可能呢?可是这怎么知道呢?还是还要敲的。很明显,以比树套树的代码慢一倍的代价(大约),A掉了。哈哈!到现在好像还真的没怎么看过分块A不掉的题(不过肯定是有的,是蒟蒻写的题太少,蒟蒻写的题分块几乎都能写),但是写这个不利于自身水平的提高啊!(不到迫不得已,还是少写分块吧!)

 1 #include
 2 #include
 3 #include
 4 #include
 5 #include
 6 #define ll long long
 7 #define rep(i,j,k) for(int i = j; i <= k; i++)
 8 #define down(i,j,k) for(int i = j; i >= k; i--)
 9 #define maxn 323
10 #define inf 0x7fffffff
11 using namespace std;
12 
13 vector<int> s[maxn];
14 int pos[100233], v[100233], t[100233];
15 bool vis[100233];
16 int n, m;
17 
18 int lower(int x ) { return x & (-x); }
19 int getans(int x)
20 {
21     int ans = 0; for(; x; x -= lower(x) ) ans += t[x];
22     return ans;
23 }
24 
25 int read()
26 {
27     int s = 0, t = 1; char c = getchar();
28     while( !isdigit(c) ){
29         if( c == - ) t = -1; c = getchar();
30     }
31     while( isdigit(c) ){
32         s = s * 10 + c - 0; c = getchar();
33     }
34     return s * t;
35 }
36 
37 int get_max(int r,int num)
38 {
39     int last = r / maxn; int tmp = 0;
40     rep(i,0,last-1) {
41         tmp += (s[i].size()-1-(upper_bound(s[i].begin(),s[i].end(),num)-s[i].begin()));
42     }
43     int begin = last*maxn;
44     rep(i,begin,r){
45         if( !vis[i] && v[i] > num ) tmp++;
46     }
47     //cout<<" a "<
48     return tmp;
49 }
50 
51 int get_min(int l,int num)
52 {
53     int begin = l / maxn; int tmp = 0;
54     rep(i,begin+1,n/maxn){
55         tmp += (lower_bound(s[i].begin(),s[i].end(),num)-s[i].begin());
56     }
57     int last = (begin+1)*maxn-1;
58     rep(i,l,min(last,n)){
59     //    cout<60     //        cout<<"k "<
61         if( !vis[i] && v[i] ;
62     } 
63 //    cout<<" i "<
64     return tmp;
65 }
66 
67 void update(int pos,int num)
68 {
69     int x = pos / maxn;
70 //    cout<<"U "<
71     s[x].erase(lower_bound(s[x].begin(),s[x].end(),num));
72     vis[pos] = 1;
73 }
74 
75 int main()
76 {
77     n = read(), m = read(); ll ans = 0;
78     rep(i,0,maxn) s[i].push_back(inf); 
79     rep(i,1,n){
80         v[i] = read(); pos[v[i]] = i; s[i/maxn].insert(lower_bound(s[i/maxn].begin(),s[i/maxn].end(),v[i]),v[i]);
81         ans += (getans(n)-getans(v[i]-1));
82         for(int x = v[i]; x <= n ; x += lower(x) ) t[x]++;
83     }
84     memset(t,0,sizeof(t));
85     rep(i,1,m){
86         printf("%lld\n", ans);
87         int x = read(), po = pos[x];
88         ans -= (get_max(po-1,x)+get_min(po+1,x));
89         update(po,x);
90         //cout<
91     }
92     return 0;
93 }

据说此题还有 cdq分治写法,我也orz一下。(这个明天再写了)

BZOJ3295 动态逆序对 树套树, 树状数组套线段树(主席树)


推荐阅读
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了指针的概念以及在函数调用时使用指针作为参数的情况。指针存放的是变量的地址,通过指针可以修改指针所指的变量的值。然而,如果想要修改指针的指向,就需要使用指针的引用。文章还通过一个简单的示例代码解释了指针的引用的使用方法,并思考了在修改指针的指向后,取指针的输出结果。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
author-avatar
香水百合-2012
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有