可持久化数据结构(平衡树、trie树、线段树) 总结

然而好像没有平衡树

还是题解包:

T1:森林

树上主席树+启发式合并。

然而好像知道标签就没啥了。在启发式合并时可以顺手求lca

然而这题好像可以时间换空间(回收空间)

T2:影魔

难点在于考虑贡献的来源

考虑一个区间两端点和区间最值(不含端点)的关系

小,中,大:贡献p1

大,小,大:贡献p2

大,中,小:贡献p1

则预处理出每个点左右第一个比它大的数的位置,设为l和r

则l会对r有p2的贡献,l会对i+1~r-1产生p1的贡献,同理r会对l+1~i-1产生p1的贡献。

用线段树维护扫描线,正向,逆向分别扫一遍,先把贡献都加进线段树,扫到某个点时先统计贡献再在线段树中减掉贡献。

具体实现见代码

  1 #include<bits/stdc++.h>
  2 #define LL long long
  3 #define N 200050
  4 using namespace std;
  5 struct node{int l,r,id;LL ans;}q[N];
  6 const int inf=1000000007;
  7 int n,m,p1,p2;
  8 int a[N];
  9 int l[N],r[N],dq[N],ba;
 10 vector<pair<int,int> >v[N];
 11 #define pb push_back
 12 #define mmp make_pair
 13 #define F first
 14 #define S second
 15 inline bool cmp1(const node &a,const node &b){return a.l<b.l;}
 16 inline bool cmp2(const node &a,const node &b){return a.r>b.r;}
 17 inline bool cmp(const node &a,const node &b){return a.id<b.id;}
 18 struct Segment_tree{
 19     LL sum[N<<2],tag[N<<2];
 20     inline void clear(){
 21         memset(sum,0,sizeof(sum));
 22         memset(tag,0,sizeof(tag));
 23     }
 24     inline void upd(int g){sum[g]=sum[g<<1]+sum[g<<1|1];}
 25     inline void down(int g,int l,int m,int r)
 26     {
 27         tag[g<<1]+=tag[g];
 28         tag[g<<1|1]+=tag[g];
 29         sum[g<<1]+=tag[g]*(m-l+1);
 30         sum[g<<1|1]+=tag[g]*(r-m);
 31         tag[g]=0;return;
 32     }
 33     inline void add(int g,int l,int r,int x,int y,int v){
 34         if(l>y||r<x)return;
 35         if(l>=x&&r<=y){sum[g]+=v*(r-l+1);tag[g]+=v;return;}
 36         const int m=l+r>>1;
 37         if(tag[g])down(g,l,m,r);
 38         add(g<<1,l,m,x,y,v);
 39         add(g<<1|1,m+1,r,x,y,v);
 40         upd(g);
 41     }
 42     inline LL ask(int g,int l,int r,int x,int y)
 43     {
 44         if(l>y||r<x)return 0;
 45         if(l>=x&&r<=y)return sum[g];
 46         const int m=l+r>>1;
 47         if(tag[g])down(g,l,m,r);
 48         return ask(g<<1,l,m,x,y)+ask(g<<1|1,m+1,r,x,y);
 49     }
 50 }T;
 51 int main()
 52 {
 53 //    freopen("da.in","r",stdin);
 54     scanf("%d%d%d%d",&n,&m,&p1,&p2);
 55     for(int i=1;i<=n;++i)scanf("%d",&a[i]);
 56     for(int i=1;i<=m;++i)
 57         scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
 58     a[0]=inf;a[n+1]=inf-1;
 59
 60     for(int i=1;i<=n+1;++i){
 61         while(a[i]>a[dq[ba]]){
 62             r[dq[ba]]=i;
 63             v[l[dq[ba]]].pb(mmp(dq[ba]+1,i-1));
 64             --ba;
 65         }
 66         l[i]=dq[ba];dq[++ba]=i;
 67     }
 68 //    for(int i=1;i<=n;++i)
 69 //        printf("l[%d]=%d r[%d]=%d\n",i,l[i],i,r[i]);
 70
 71
 72
 73
 74     sort(q+1,q+m+1,cmp1);
 75     for(int i=1;i<=n;++i){
 76         if(r[i]!=i+1)T.add(1,1,n,r[i],r[i],p1);
 77         for(int j=v[i].size()-1;~j;--j)
 78             T.add(1,1,n,v[i][j].F,v[i][j].S,p2);
 79     }
 80     for(int i=1,k=1;i<=n;++i){
 81         while(q[k].l==i&&k<=m){
 82             q[k].ans+=T.ask(1,1,n,i,q[k].r);
 83             ++k;
 84         }
 85         if(r[i]!=i+1)T.add(1,1,n,r[i],r[i],-p1);
 86         for(int j=v[i].size()-1;~j;--j)
 87             T.add(1,1,n,v[i][j].F,v[i][j].S,-p2);
 88         v[i].clear();
 89     }
 90
 91     for(int i=1;i<=n;++i)
 92         if(r[i])v[r[i]].push_back(mmp(l[i]+1,i-1));
 93     sort(q+1,q+m+1,cmp2);
 94     for(int i=n;i;--i){
 95         if(l[i]!=i-1)T.add(1,1,n,l[i],l[i],p1);
 96         for(int j=v[i].size()-1;~j;--j)
 97             T.add(1,1,n,v[i][j].F,v[i][j].S,p2);
 98     }
 99     for(int i=n,k=1;i;--i){
100         while(q[k].r==i&&k<=m){
101             q[k].ans+=T.ask(1,1,n,q[k].l,i);
102             ++k;
103         }
104         if(l[i]!=i-1)T.add(1,1,n,l[i],l[i],-p1);
105         for(int j=v[i].size()-1;~j;--j)
106             T.add(1,1,n,v[i][j].F,v[i][j].S,-p2);
107     }
108 //    printf("%d %d %lld\n",q[2].l,q[2].r,q[2].ans);
109     sort(q+1,q+m+1,cmp);
110     for(int i=1;i<=m;++i)
111         printf("%lld\n",q[i].ans+1ll*(q[i].r-q[i].l)*p1);
112     return 0;
113 }

原文地址:https://www.cnblogs.com/loadingkkk/p/12063886.html

时间: 2024-08-09 22:27:35

可持久化数据结构(平衡树、trie树、线段树) 总结的相关文章

POJ2104 K-th Number 不带修改的主席树 线段树

http://poj.org/problem?id=2104 给定一个序列,求区间第k小 通过构建可持久化的点,得到线段树左儿子和右儿子的前缀和(前缀是这个序列从左到右意义上的),然后是一个二分的get操作. 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #define LL long lo

#树# #线段树#

线段树 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b].因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度. 模板: 建树 1 void Pushup(int rt){//根节点

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

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

BZOJ_3196_二逼平衡树(树套树:线段树+Treap)

描述 可以处理区间问题的平衡树. 分析 树套树.可以用线段树套Treap.人生第一道树套树的题... op1:如果在整区间,直接在该区间的treap上求解.否则分两个区间求解,然后相加.最后+1. op2:这个不太好直接做,可以二分,每次假定一个值,用这个值去做op1,以此求得一个rank=k+1的数,求rank=k的数等价与求这个数的前驱pre. op3:先删后加. op4&op5:如果在整区间,直接在该区间的treap上求解,否则分量个区间求解,pre取最大值,suc取最小值.注意有些数在有

COJ 1010 WZJ的数据结构(十) 线段树区间操作

传送门:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=1001 WZJ的数据结构(十) 难度级别:D: 运行时间限制:3000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,高效执行以下过程: #include<iostream>using namespace std;const int maxn=100010;int A[maxn];int tp,ql,qr,v;int

刷题总结——二逼平衡树(bzoj3224线段树套splay)

题目: Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行有n个数,表示有序序列下面有m行,opt表示操作标号若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r

树套树-线段树套平衡树

树套树留坑 线段树套平衡树: 二逼平衡树 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<cmath> #include<map> #include<bitset> #pragma GCC optimize(2) #define rep(i,a,b) for(i

Bzoj 1901: Zju2112 Dynamic Rankings 树套树,线段树,平衡树,Treap

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 6471  Solved: 2697[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i

「BZOJ3600」没有人的算术 替罪羊树+线段树

题目描述 过长--不想发图也不想发文字,所以就发链接吧-- 没有人的算术 题解 \(orz\)神题一枚 我们考虑如果插入的数不是数对,而是普通的数,这就是一道傻题了--直接线段树一顿乱上就可以了. 于是我们现在只需要解决一个问题--维护这些数的大小关系. 由于这些数具有有序性,我们可以将这些数的值重记为一个数,这样就可以无脑地比较了.并且,由于这些值的大小可能会随着插入而更改,所以要用一棵平衡树来维护. 那么问题来了,这个数取什么值比较好呢? 首先当然可以是排名,不过如果使用排名,每次访问值的时