洛谷试炼场 提高模板-nlogn数据结构

树状数组-区间求和

P3374 【模板】树状数组 1

 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 using namespace std;
 8 int read(){
 9     int x=0,f=1;char ch=getchar();
10     while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
11     while(ch>=‘0‘ && ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
12     return x*f;
13 }
14 const int mxn=500010;
15 int n,m;
16 int t[mxn];
17 void add(int x,int v){
18     while(x<mxn){t[x]+=v;x+=x&-x;}
19 }
20 int smm(int x){
21     int res=0;
22     while(x){
23         res+=t[x];
24         x-=x&-x;
25     }
26     return res;
27 }
28 int main(){
29     int op,x,k;
30     n=read();m=read();
31     int i,j;
32     for(i=1;i<=n;i++){
33         x=read();
34         add(i,x);
35     }
36     for(i=1;i<=m;i++){
37         op=read();x=read();k=read();
38         if(op==1){
39             add(x,k);
40         }
41         else{
42             printf("%d\n",smm(k)-smm(x-1));
43         }
44     }
45     return 0;
46 }

树状数组1

树状数组-差分

P3368 【模板】树状数组 2

 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 using namespace std;
 8 int read(){
 9     int x=0,f=1;char ch=getchar();
10     while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
11     while(ch>=‘0‘ && ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
12     return x*f;
13 }
14 const int mxn=500010;
15 int n,m;
16 int t[mxn];
17 void add(int x,int v){
18     while(x<mxn){t[x]+=v;x+=x&-x;}
19 }
20 int smm(int x){
21     int res=0;
22     while(x){
23         res+=t[x];
24         x-=x&-x;
25     }
26     return res;
27 }
28 int main(){
29     int op,x,k;
30     n=read();m=read();
31     int i,j;
32     for(i=1;i<=n;i++){
33         x=read();
34         add(i,x);
35         add(i+1,-x);
36     }
37     for(i=1;i<=m;i++){
38         op=read();
39         if(op==1){
40             x=read();k=read();op=read();
41             add(x,op);
42             add(k+1,-op);
43         }
44         else{
45             x=read();
46             printf("%d\n",smm(x));
47         }
48     }
49     return 0;
50 }

树状数组2

线段树-区间加 区间乘

P3373 【模板】线段树 2

  1 /*by SilverN*/
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<cmath>
  7 #define ls l,mid,rt<<1
  8 #define rs mid+1,r,rt<<1|1
  9 #define lc rt<<1
 10 #define rc rt<<1|1
 11 using namespace std;
 12 const int mxn=1000000;
 13 long long n,p;
 14 long long a[mxn];
 15 struct node{
 16     long long sum;
 17     long long mu;
 18     long long add;
 19 }tr[mxn];
 20 void pushdown(int rt,int m){
 21     tr[lc].sum=(tr[lc].sum*tr[rt].mu+(m-(m>>1))*tr[rt].add)%p;
 22                                 //m-(m>>1)得到区间范围的一半,也就是左子树的范围
 23     tr[rc].sum=(tr[rc].sum*tr[rt].mu+(m>>1)*tr[rt].add)%p;
 24     tr[lc].mu=tr[lc].mu*tr[rt].mu%p;
 25     tr[rc].mu=tr[rc].mu*tr[rt].mu%p;
 26     tr[lc].add=(tr[lc].add*tr[rt].mu+tr[rt].add)%p;
 27     tr[rc].add=(tr[rc].add*tr[rt].mu+tr[rt].add)%p;
 28     tr[rt].mu=1;tr[rt].add=0;
 29     return;
 30 }
 31 void Build(int l,int r,int rt){
 32     tr[rt].mu=1;tr[rt].add=0;
 33     if(l==r){
 34         tr[rt].sum=a[l];
 35         return;
 36     }
 37     int mid=(l+r)>>1;
 38     Build(ls);
 39     Build(rs);
 40     tr[rt].sum=(tr[rt<<1].sum+tr[rt<<1|1].sum)%p;
 41     return;
 42 }
 43 void add(int L,int R,int l,int r,int rt,int v){
 44     if(L<=l && r<=R){
 45         tr[rt].sum=(tr[rt].sum+v*(r-l+1))%p;//本身值累加区间新增值
 46         tr[rt].add=(tr[rt].add+v)%p;//标记累加
 47         return;
 48     }
 49     pushdown(rt,r-l+1);//下传
 50     int mid=(l+r)>>1;
 51     if(L<=mid)add(L,R,ls,v);
 52     if(R>mid)add(L,R,rs,v);
 53     tr[rt].sum=(tr[lc].sum+tr[rc].sum)%p;
 54     return;
 55 }
 56 void multi(int L,int R,int l,int r,int rt,int v){
 57     if(L<=l && r<=R){
 58         tr[rt].add=(tr[rt].add*v)%p;
 59         tr[rt].mu=(tr[rt].mu*v)%p;
 60         tr[rt].sum=(tr[rt].sum*v)%p;
 61         return;
 62     }
 63     pushdown(rt,r-l+1);
 64     int mid=(l+r)>>1;
 65     if(L<=mid)multi(L,R,ls,v);
 66     if(R>mid)multi(L,R,rs,v);
 67     tr[rt].sum=(tr[lc].sum+tr[rc].sum)%p;
 68     return;
 69 }
 70 long long query(int L,int R,int l,int r,int rt){//查询
 71     if(L<=l && r<=R)return tr[rt].sum%p;
 72     int mid=(l+r)>>1;
 73     pushdown(rt,r-l+1);
 74     long long res=0;
 75     if(L<=mid)res=(res+query(L,R,ls))%p;
 76     if(R>mid)res=(res+query(L,R,rs))%p;
 77     tr[rt].sum=(tr[lc].sum+tr[rc].sum)%p;
 78     return res%p;
 79 }
 80 int main(){
 81     int M;
 82     scanf("%lld%lld%lld",&n,&M,&p);
 83     int i,j;
 84     for(i=1;i<=n;i++)scanf("%lld",&a[i]);
 85     Build(1,n,1);
 86     int op,g,t,c;
 87     while(M--){
 88         scanf("%d%d%d",&op,&t,&g);
 89         if(op==1){//乘
 90             scanf("%d",&c);
 91             multi(t,g,1,n,1,c);
 92         }
 93         if(op==2){//加
 94             scanf("%d",&c);
 95             add(t,g,1,n,1,c);
 96         }
 97         if(op==3){//询问
 98             long long ans=query(t,g,1,n,1);
 99             printf("%lld\n",ans%p);
100         }
101     }
102     return 0;
103 }

线段树区间修改

二叉堆

P3378 【模板】堆

 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 using namespace std;
 8 const int mxn=1200000;
 9 int read(){
10     int x=0,f=1;char ch=getchar();
11     while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
12     while(ch>=‘0‘ && ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
13     return x*f;
14 }
15 int tp[mxn];
16 int cnt=0;
17 void add(int x){
18     tp[++cnt]=x;
19     int now=cnt;
20     while(now>1){
21         int nxt=now/2;
22         if(tp[nxt]<=tp[now])return;
23         swap(tp[nxt],tp[now]);
24         now=nxt;
25     }
26     return;
27 }
28 int del_head(){
29     int res=tp[1];
30     tp[1]=tp[cnt--];
31     int now=1;
32     while(now<=cnt/2){
33         int nxt=now<<1;
34         if(nxt<cnt && tp[nxt+1]<tp[nxt])nxt++;
35         if(tp[now]>tp[nxt]){
36             swap(tp[now],tp[nxt]);
37             now=nxt;
38         }
39         else return res;
40     }
41     return res;
42 }
43 int main(){
44     int n;
45     n=read();
46     int op,x,y;
47     int i,j;
48     for(i=1;i<=n;i++){
49         op=read();
50         switch(op){
51             case 1:{x=read();add(x);break;}
52             case 2:{printf("%d\n",tp[1]);break;}
53             case 3:{del_head();break;}
54         }
55     }
56     return 0;
57 }

最小堆

此处是最小堆

时间: 2024-08-09 02:21:00

洛谷试炼场 提高模板-nlogn数据结构的相关文章

洛谷P3385 【模板】负环 DFS-SPFA 判负环 图论

洛谷P3385 [模板]负环 图论 今天get了 一个 DFS-SPFA 判负环的方法 一般的 BFS-SPFA 判负环 一般就是 不停地做,如果某点第 n+1次加入队列中,那么说明这个图存在负环然而我并不会证明,期望复杂度是 O(kM) k 大约是在 2 左右 但是其实对于一些极限数据,最坏可以把他卡到 O( NM) 额,这就直接炸飞了是不是,而且据说,一些数据比较强的题目,总会想到卡一卡SPFA的, 然后我们换一种思路 因为题目中一定存在一种 负环对吧,所以说假如你某段路径权值和为自然数的时

洛谷P3387 【模板】缩点

洛谷P3387 [模板]缩点 题目背景 缩点+DP 题目描述 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次. 输入输出格式 输入格式: 第一行,n,m 第二行,n个整数,依次代表点权 第三至m+2行,每行两个整数u,v,表示u->v有一条有向边 输出格式: 共一行,最大的点权之和. 输入输出样例 输入样例#1: 2 2 1 1 1 2 2 1 输出样例#1: 2 说

洛谷 P3380 【模板】二逼平衡树(树套树)

洛谷 P3380 [模板]二逼平衡树(树套树) 线段树套treap: 就是线段树每个节点放一个treap.建树复杂度应该是$n log n$,操作1,3,4,5的复杂度是$(log n)^2$,操作2的复杂度是$(log n)^3$. 操作3:找到线段树的对应叶子节点后找到要删除的值,在回溯的时候更新线段树相关的每一个节点(在treap中去掉要删除的值,再加入要加入的值) 操作1:将操作转化为统计(这个区间[l,r]内小于x的数的个数)+1.那么通过线段树将区间分解,然后对分解出的每一个区间对应

洛谷P3372 【模板】线段树 1

P3372 [模板]线段树 1 153通过 525提交 题目提供者HansBug 标签 难度普及+/提高 提交  讨论  题解 最新讨论 [模板]线段树1(AAAAAAAAA- [模板]线段树1 洛谷评测机出问题了吗? 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接

在洛谷3369 Treap模板题 中发现的Splay详解

本题的Splay写法(无指针Splay超详细) 前言 首先来讲...终于调出来了55555...调了整整3天..... 看到大部分大佬都是用指针来实现的Splay.小的只是按照Splay的核心思想和原理来进行的.可能会有不妥之处,还请大佬们指出,谢谢! 那么这个题解存在的意义就是让不会敲Splay的人额...会敲Splay啦... 基本思想 数据结构 对于Splay,我定义了一个class类(当成struct就行啦...个人习惯不同啦),定义名称为“Splay”. 之后在类中,我定义了Splay

洛谷 P1439 【模板】最长公共子序列

神TM模板..我本来想休闲一下写点水题的... 开始做的时候直接敲了一个O(N2)的算法上去,编译的时候才发现根本开不下.. 好了,谈回这道题. 先不加证明的给出一种算法. 若有一组数据 2 4 2 5 1 3 2 5 4 1 3 那么我们令 4 2 5 1 3 | | | | | 1 2 3 4 5 第三行的数据就变成 2 3 1 4 5 很明显,答案是这个数据的最长上升子序列,即4 == 2 3 4 5,即原数列的2 5 1 3. 现在来大概的介绍一下这样做的原因. 首先,观察题目,注意到这

洛谷 P3375 【模板】KMP字符串匹配 || HDU 1686 Oulipo || kmp

HDU-1686 P3375 kmp介绍: http://www.cnblogs.com/SYCstudio/p/7194315.html http://blog.chinaunix.net/uid-8735300-id-2017161.html(mp&kmp) http://www-igm.univ-mlv.fr/~lecroq/string/node8.html(mp&kmp,看上去很正确的例程) http://blog.csdn.net/joylnwang/article/detai

城堡——搜索,稍微有点水,令人惊异的是被洛谷评为提高+

此题在Openjudge NOI 上面还有一个阉割版,也就是只求最大房间大小和房间总数量,在2.5搜索专题里面.阉割版不需要多思考就可以做出来,不过原版也只是在想一步而已,鉴于数据不是特别大.可以看到我的做法就是先BFS 算房间,把每个块所属的房间和大小记录好,然后再 按 顺 序 枚举每个块,从而得出做大合并房间和推倒位置.判断墙的存在时用了位运算,因为题目的1248明显就是暗示要这么搞最方便. 1 #include<queue> 2 #include<iostream> 3 us

洛谷P3380 【模板】二逼平衡树(树套树,树状数组,线段树)

洛谷题目传送门 emm...题目名写了个平衡树,但是这道题的理论复杂度最优解应该还是树状数组套值域线段树吧. 就像dynamic ranking那样(蒟蒻的Sol,放一个link骗访问量233) 所有的值(包括初始a数组,操作1.3.4.5的k)全部先丢进去离散化 对于1操作查比它小的数,挑log棵线段树,找区间小于这个数的个数+1,这个还比较好像 操作2就是dynamic ranking,log棵线段树一起加减,像静态主席树求第k小一样跳,操作3 dynamic ranking里也有 操作4先