上古时期(大雾)的数据结构pdf

分块+点分治+Treap

byWYCby\ WYCby WYC


Part1 分块


概念

就是将nnn个数分成若干个块,然后要处理的时候整块一起的加上局部的直接暴力。

如果将块的大小分配好一般每次都是O(n)O(\sqrt n)O(n)的。

而且因为十分暴力,所以有很多优秀的性质。

扣的图


实现方法

怎么暴力的还用讲实现方法,好吧,讲一些基础的

要求区间求和,区间修改

对于每个块维护一个所以值的和和一个懒惰

区间求和时,将整块的直接加上去,局部的暴力加上去

区间修改时,将整块的懒惰标记,局部的暴力加上去

对于局部修改时,如果有懒惰就直接暴力将整个块都修改,然后去掉懒惰。

时间复杂度每个都是O(n)O(\sqrt n)O(n)

是不是十分优秀


例题

在例题中体现优秀的性质


P4168-[Violet]蒲公英

题目大意

询问区间众数

解题思路

将数字离散化,然后分块。对于数组vi,j,kv_{i,j,k}vi,j,k,表示i∼ji\sim jij个块,kkk的个数。对于询问(l,r)(l,r)(l,r),将整块的直接累计,然后局部的直接暴力。

时间复杂度:O(NT2+MNT)O(NT^2+\frac{MN}{T})O(NT2+TMN),根据LYD的说法,让T≈n3T\approx \sqrt[3]nT3n的话,时间复杂度就可以在O(N53)O(N^{\frac{5}{3}})O(N35)级别。

代码写优美些或者加点优化就可以过。

code

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define Tn 40
#define N 40010
using namespace std;
int n,m,L[Tn],R[Tn],v[Tn][Tn][N],l,r,num[N];
int z[N],w[N],a[N],cnt,k[N],t,T,pos[N],x;
bool cmp(int x,int y)//排序
{return z[x]<z[y];}
void begins()//预处理
{for(int i=1;i<=t;i++){L[i]=(i-1)*T+1;R[i]=i*T;}if(R[t]<n) t++,L[t]=R[t-1]+1,R[t]=n;//计算边界for(int i=1;i<=t;i++)for(int j=i;j<=t;j++)for(int k=L[i];k<=R[j];k++)v[i][j][a[k]]++;//计算v数组
}
int ask(int l,int r)
{int p=pos[l],q=pos[r];if(p-q<=2){memset(k,0,sizeof(k));for(int i=l;i<=r;i++)k[a[i]]++;}else{p++;q--;for(int i=1;i<=cnt;i++)k[i]=v[p][q][i];//直接累计for(int i=l;i<L[p];i++)//暴力统计k[a[i]]++;for(int i=R[q]+1;i<=r;i++)//暴力统计*2k[a[i]]++;}int mark=1;for(int i=2;i<=cnt;i++)//找众数if(k[i]>k[mark]) mark=i;return w[mark];
}
int main()
{scanf("%d%d",&n,&m);t=(int)pow(double(n),1.0/3);T=n/t;for(int i=1;i<=n;i++){scanf("%d",&z[i]);num[i]=i;}sort(num+1,num+1+n,cmp);z[0]=-1;for(int i=1;i<=n;i++)//离散化{if(z[num[i]]!=z[num[i-1]]) cnt++,w[cnt]=z[num[i]];;a[num[i]]=cnt;}T=n/t;begins();for(int i=1;i<=m;i++){scanf("%d%d",&l,&r);l=(l+x-1)%n+1;r=(r+x-1)%n+1;if(l>r) swap(l,r);printf("%d\n",x=ask(l,r));}
}

优秀性质1

对于块你可以构建二维的,就十分优秀。

如这道题中vi,j,kv_{i,j,k}vi,j,k对于块进行了二维


P4879-ycz的妹子

题目大意

有若干种操作

  1. Cxy:ax−=yC\ x\ y:a_x-=yC x y:ax=y
  2. Ixy:I\ x\ y:I x y:加一个(原本有的话就改变)ax=ya_x=yax=y
  3. Q:Q:Q:询问所以数的和
  4. Dx:D\ x:D x:删除第xxx个(有的才算)数。

解题思路

我们发现只有单点修改,和全部求和。所以ansansans表示全部的和,然后前三个操作就搞定了。
第四个操作维护一个分块,记录每块有的数的个数,然后找到目标在那个块,之后这个块里暴力寻找,这个操作时间负责度O(n)O(\sqrt n)O(n)

总体时间复杂度:O(nn)O(n\sqrt n)O(nn)

codecodecode

#include<cstdio>
#include<cmath>
#include<iostream>
#define ll long long
#define N 500000
#define T 1000
using namespace std;
ll n,m,a[N+10],ans,no[N+10],x,y,t;
ll L[T],R[T],num[T],pos[N+10];
char c;
int main()
{scanf("%lld%lld",&n,&m);t=sqrt(N);for(ll i=1;i<=N;i++){pos[i]=(i-1)/t+1;if(i>n)no[i]=1;}for(ll i=1;i<=n;i++){scanf("%lld",&a[i]);num[pos[i]]++;ans+=a[i];}for(ll i=1;i<=m;i++){cin>>c;if(c=='Q')printf("%lld\n",ans);else if(c=='I'){scanf("%lld%lld",&x,&y);ans-=a[x];a[x]=y;ans+=y;n=max(n,x);if(no[x]){no[x]=0;num[pos[x]]++;}}else if(c=='C'){scanf("%lld%lld",&x,&y);if(no[x]) continue;ans-=y;a[x]-=y;}else if(c=='D'){scanf("%lld",&x);ll k=1;while(x-num[k]>0)x-=num[k],k++;for(int i=(k-1)*t+1;i<=min(k*t,n);i++){if(!no[i]) --x;if(!x){num[k]--;no[i]=1;ans-=a[i];a[i]=0;break;}}}}
}

优秀性质2

一个块一个块的跑,利用储存块的信息快速锁定目标


P3203-[HNOI2010]弹飞绵羊

这个就强大了

题目大意

nnn个装置。到第iii个装置会被往前弹aia_iai个。
两种操作
修改aia_iai和询问从iii出发要多少次弹射可以弹出去。

解题思路

first,本题正解LCT。然而分块可以轻松过掉

分块。对于每个点,维护要多少步弹出该块和弹出去后弹到哪里。
询问就直接根据两个数据,修改就直接重构整个块。

时间复杂度:O(nn)O(n\sqrt n)O(nn)

code

#include<cstdio>
#include<cmath>
#define N 200010
#define T 500
using namespace std;
int n,m,x,t,a[N],L[T],R[T],step[N],to[N],pos[N];
void pre_work()//预处理
{for(int i=1;i<=t;i++)//块边界{L[i]=(i-1)*t+1;R[i]=i*t;}if(R[t]!=n) t++,L[t]=R[t-1]+1,R[t]=n;for(int i=1;i<=t;i++)for(int j=R[i];j>=L[i];j--){if(j+a[j]<=R[i]) step[j]=step[j+a[j]]+1,to[j]=to[j+a[j]];else step[j]=1,to[j]=j+a[j];pos[j]=i;}//初始数据
}
int ask(int x)//询问
{int ans=0;while(x<=n)ans+=step[x],x=to[x];return ans;
}
void change(int i)//重构块
{for(int j=R[i];j>=L[i];j--)if(j+a[j]<=R[i]) step[j]=step[j+a[j]]+1,to[j]=to[j+a[j]];else step[j]=1,to[j]=j+a[j];
}
int main()
{scanf("%d",&n);t=sqrt(n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);pre_work();scanf("%d",&m);for(int i=1;i<=m;i++){scanf("%d",&x);if(x==1){scanf("%d",&x);x++;printf("%d\n",ask(x));}else{scanf("%d",&x);x++;scanf("%d",&a[x]);change(pos[x]);}}
}

优秀性质3

本题最强大的地方是在于当他修改时,直接暴力重构了整个块,十分强大


性质总结

对于分块,最强大的操作就是暴力。因为无论怎么暴力,只要每次保证不用重构太多块,基本都是O(n)O(\sqrt n)O(n)

然后就算根据每个块的信息找一遍,也依据是O(n)O(\sqrt n)O(n)

而且n2=n\sqrt n^2=nn2=n所以我们可以猥琐欲为的将数据当做可以n2n^2n2的来看


分块-终章

“局部暴力,大段维护”。当然分块十分简单,性质也十分优秀,也很好写。

but!but!but!,时间复杂度终究是O(nn)O(n\sqrt n)O(nn)的,如果出题人让你用O(nlogn)O(n\ log\ n)O(n log n)也没有办法

还是老老实实写别的数据结构对吧


Part2-点分治


概念

首先,点分治无论在速度还是处理问题方面都会被树上启发式合并吊打,而且我也不知道为什么他会被分进数据结构里,但是不重要!

点分治在树上进行分治,每次将树分治成若干棵不同的子树处理。

实现方法

一般用于处理树上路径长度的问题

这里举LuoguLuoguLuogu的模板P3806P3806P3806

一棵树(无向),mmm个询问求长度为kkk的路径存不存在。

对于以ppp为根的子树

然后考虑路径种类,其实只有两种

  1. 经过根节点
  2. 包含在某一棵子树中

对于1,我们将路径分成两半.

求出根节点里每个点的距离did_idi,和每个节点位于那个子树bib_ibi

要求满足bx≠byb_x\neq b_ybx=bydx+dy=kd_x+d_y=kdx+dy=k

这时候定义函数Calc(p)Calc(p)Calc(p)表示以ppp为根的子树上上述路径的条数

而路径二就直接分治让子树再处理一遍就好了。

现在是考虑Calc(p)Calc(p)Calc(p)如何定义的问题。

因为数据很小,用lonxlon_xlonx表示是否存在长度为xxx的路径

然后我们对于每颗子树,先用之前的lonlonlon计算一下询问

之后在将这棵子树加入lonlonlon数组

然后在子树之中继续处理

时间复杂度:O(TNlogN)O(TN\ log \ N)O(TN log N)TTT为树的层数

可是如果树是一条链,那么时间就会退化为O(N2logN)O(N^2\ log\ N)O(N2 log N)

但是如果我们每次以子树的重心作为新分治的根,那么最多只会有logNlog\ Nlog N层。

时间就可以稳在O(Nlog2N)O(N\ log^2\ N)O(N log2 N)


Part 3:Treap

概念

TreapTreapTreap就是平衡树的一种,所谓平衡树就是要求稳定在lognlog\ nlog n层左右的BSTBSTBST,为什么要稳定层数,我们等会再讲。

实现方法

TreapTreapTreap的实现方法之前要先将BSTBSTBST

BSTBSTBST

所谓BST,就是二叉查找树。

二叉查找树有个优秀的性质,那就是对于每个节点,左子节点的权值比它小,右子节点比它大。

这样我们就可以愉快的干很多事,比如查找前驱,后继,排名啊

明人不说暗话,先来将实现方法

开始先构建两个节点−inf-infinfinfinfinf,以任意一个为根

    int New(int new_val){val[++tot]=new_val;dat[tot]=rand();cnt[tot]=size[tot]=1;return tot;}void Build(){New(-INF);New(INF);root=1;r[1]=2;Updata(root);}

1[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I4PJVqvd-1576912899795)(https://i.loli.net/2019/01/20/5c446542aac73.png)]

插入andandand删除:

插入一个数时,先从根开始。对于走到的每一个点,如果比它小就往左,不然就往右走。知道找到一个空余的位置就插入。

    void Insert(int &p,int num){if(p==0){p=New(num);return;}//如果有空位了if(num==val[p]){cnt[p]++;Updata(p);return;}//已经有这个数了if(num<val[p]){Insert(l[p],num);}//小于往左else{Insert(r[p],num);}//大于往右Updata(p);//更新数据}

删除也是根据那个走法找到位置,然后删除

删除时注意将子节点接上去

void Remove(int val){int &p=root;while(p){if(val==a[p].val) break;p=val<a[p].val?a[p].l:a[p].r;}if(p==0) return;if(a[p].l==0){p=a[p].r}//没左接右else if(a[p].r==0){p=a[p].l;}//没右接左else{//求个后继int next=a[p].r;while(a[next].l>0) next=a[next].l;//next没有左子树,直接删除Romove(a[next].val);//令节点next代替节点p的位置a[next].l=a[p].r;a[next].r=a[p].r;p=next;}
}

求前驱/后继

valvalval后继就是比valvalval大的最小的数。

对于求后继,我们可以用一步一步往下走的方法,并在路上更新答案ansansans,直到走到valvalval的位置或结束时。

这时有3种结果

  1. 没有valvalval这个节点。那就直接取ansansans
  2. valvalval,但没有右子树。也是直接取ansansans
  3. 找到valvalval,且也有右子树。走到右边,然后一直往左走,就是valvalval的后继

前驱同理

    int GetPre(int num){int ans=1;int p=root;while(p){if(num==val[p]){//找到val节点if(l[p]>0){p=l[p];//往左一步while(r[p]>0) p=r[p];//一直往右ans=p;//统计}break;}if(val[p]<num&&val[p]>val[ans]) ans=p;p=num<val[p]?l[p]:r[p];//走}return val[ans];}int GetNext(int num){int ans=2;int p=root;while(p){if(num==val[p]){if(r[p]>0){p=r[p];while(l[p]>0) p=l[p];ans=p;}break;}if(val[p]>num&&val[p]<val[ans]) ans=p;p=num<val[p]?l[p]:r[p];}return val[ans];}

查询一个数的排名/一个排名的数

一个数的排名就直接走到那个点,顺路根据树的大小统计前面有多少个点就好了。

一个排名的数,就根据子树大小来走就ok了。

    int GetRankByVal(int p,int num){if(p==0) return 0;if(num==val[p]) return size[l[p]]+1;if(num<val[p]) return GetRankByVal(l[p],num);return GetRankByVal(r[p],num)+size[l[p]]+cnt[p];}int GetValByRank(int p,int rank){if (p==0) return INF;if(size[l[p]]>=rank) return GetValByRank(l[p],rank);if(size[l[p]]+cnt[p]>=rank) return val[p];return GetValByRank(r[p],rank-size[l[p]]-cnt[p]);}

这就是BSTBSTBST的全部了。我们来考虑它的弊端。

每次时间就会为O(T)O(T)O(T)

如果我以单调的插入数,那么每次就会退化为O(N)O(N)O(N)

那么我们就要让这个BSTBSTBST平衡


TreapTreapTreap

TreapTreapTreap是其中一种让BSTBSTBST保持在lognlog\ nlog n层左右的一个数据结构

具体实现方法就是通过旋转,对于一个东西

graph (1).png

可以旋转为
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dTwPYOyz-1576912899796)(https://i.loli.net/2019/01/20/5c446ed9d8f17.png)]

总之就是分为左旋和右旋

    void zig(int &p){int q=l[p];l[p]=r[q];r[q]=p;p=q;Updata(r[p]);Updata(p);}void zag(int &p){int q=r[p];r[p]=l[q];l[q]=p;p=q;Updata(l[p]);Updata(p);}

只会我们对每个点,我们定义一个特征值。然后我们通过旋转让特征值满足二叉堆的性质。

只要让特征值时随机的,基本都可以维持在lognlog\ nlog n层附近。

好了,放codecodecode

#include<cstdio>
#include<algorithm>
#define INF 2147483647/3
#define N 100010
using namespace std;
int n,root;
struct Treap_node{int l[N],r[N];int val[N],dat[N];int cnt[N],size[N];int tot;int New(int new_val){val[++tot]=new_val;dat[tot]=rand();cnt[tot]=size[tot]=1;return tot;}void Updata(int p){size[p]=size[l[p]]+size[r[p]]+cnt[p];}void Build(){New(-INF);New(INF);root=1;r[1]=2;Updata(root);}int GetRankByVal(int p,int num){if(p==0) return 0;if(num==val[p]) return size[l[p]]+1;if(num<val[p]) return GetRankByVal(l[p],num);return GetRankByVal(r[p],num)+size[l[p]]+cnt[p];}int GetValByRank(int p,int rank){if (p==0) return INF;if(size[l[p]]>=rank) return GetValByRank(l[p],rank);if(size[l[p]]+cnt[p]>=rank) return val[p];return GetValByRank(r[p],rank-size[l[p]]-cnt[p]);}void zig(int &p){int q=l[p];l[p]=r[q];r[q]=p;p=q;Updata(r[p]);Updata(p);}void zag(int &p){int q=r[p];r[p]=l[q];l[q]=p;p=q;Updata(l[p]);Updata(p);}void Insert(int &p,int num){if(p==0){p=New(num);return;}if(num==val[p]){cnt[p]++;Updata(p);return;}if(num<val[p]){Insert(l[p],num);if(dat[p]<dat[l[p]]) zig(p);}else{Insert(r[p],num);if(dat[p]<dat[r[p]]) zag(p);}Updata(p);}int GetPre(int num){int ans=1;int p=root;while(p){if(num==val[p]){if(l[p]>0){p=l[p];while(r[p]>0) p=r[p];ans=p;}break;}if(val[p]<num&&val[p]>val[ans]) ans=p;p=num<val[p]?l[p]:r[p];}return val[ans];}int GetNext(int num){int ans=2;int p=root;while(p){if(num==val[p]){if(r[p]>0){p=r[p];while(l[p]>0) p=l[p];ans=p;}break;}if(val[p]>num&&val[p]<val[ans]) ans=p;p=num<val[p]?l[p]:r[p];}return val[ans];}void Remove(int &p,int num){if(p==0) return;if(num==val[p]){if(cnt[p]>1){cnt[p]--;Updata(p);return;}if(l[p]||r[p]){if(r[p]==0||dat[l[p]]>dat[r[p]])zig(p),Remove(r[p],num);elsezag(p),Remove(l[p],num);Updata(p);}else p=0;return;}num<val[p]?Remove(l[p],num):Remove(r[p],num);Updata(p);}
}a;
int main()
{a.Build();scanf("%d",&n);while(n--){int opt,x;scanf("%d%d",&opt,&x);switch(opt){case 1:a.Insert(root,x);break;case 2:a.Remove(root,x);break;case 3:printf("%d\n",a.GetRankByVal(root,x)-1);break;case 4:printf("%d\n",a.GetValByRank(root,x+1));break;case 5:printf("%d\n",a.GetPre(x));break;case 6:printf("%d\n",a.GetNext(x));break;}}
}

虽然基本都可以用setsetset搞定,但是还是可以做很多NBNBNB的好东西的。


Part4:树链剖分

概念

将树分割成若干条链来处理,将树上的问题转换为线性问题

实现方法

实现概念

学树链剖分之前我们先来getgetget一些前置知识

重儿子:子树最大的一个儿子

轻儿子:其他儿子

重边:连接重儿子的边

轻边:其他边

重路径:重边的路径

还有一个重要性质:从根到任何一个点的轻边数不超过lognlog\ nlog n

证明:

若走到一条轻边,那么子树大小至少缩小一半,那么最多走log⁡n\log nlogn条轻边子树大小就会缩小为1

证毕

所以我们对于一条路径的轻边数量也是logloglog级的。

所以我们可以对于重路径将树进行划分。

我们来看例题:

要求支持子树修改,子树求和,路径修改,路径求和。

对于子树操作很简单,我们按照dfsdfsdfs序加入线段树,然后线段树区间修改就可以做到子树修改,可以路径问题如何解决?

这时候我们就可以用树链剖分了。我们考虑将dfsdfsdfs修改一下。

我们可以每次优先走重儿子,那么重路径在线段树上的位置就是连续的,对于一段重路径我们就可以进行区间修改了,而轻边有不会太多,所以一次操作时间复杂度是O(log2n)O(log^2\ n)O(log2 n)

代码实现

我们先跑两次dfsdfsdfs预处理

第一遍:

sonx:xson_x:xsonx:x的重儿子

depx:xdep_x:xdepx:x的深度

sizx:x​siz_x:x​sizx:x的子树大小

fx:xf_x:xfx:x的父节点

第二遍:

segx:x​seg_x:x​segx:x在线段树上的位置

idz:id_z:idz:线段树zzz位置上的节点

topx:xtop_x:xtopx:x所在重路径最浅的节点

之后我们就预处理完了。

之后我们对于路径操作可以向倍增求LCALCALCA一样,将一条路径拆分为两条路径,不过变为每次跳到topxtop_xtopx,然后跳的过程重进行用线段树进行区间修改。

codecodecode

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=200000;
int tot,cnt,n,m,s,p,ls[N],pw[N],id[N];
int siz[N],dep[N],f[N],son[N],seg[N],top[N];
struct treenode{int l,r,lazy,val;
};
struct LineTree{treenode t[N*2];void build(int x,int l,int r){t[x].l=l;t[x].r=r;if(l==r){t[x].val=pw[id[l]]%p;return;}int mid=(l+r)>>1;build(x*2,l,mid);build(x*2+1,mid+1,r);t[x].val=(t[x*2].val+t[x*2+1].val)%p;}void downdata(int x){if(t[x].lazy){(t[x*2].lazy+=t[x].lazy)%=p;(t[x*2].val+=t[x].lazy*(t[x*2].r-t[x*2].l+1))%=p;(t[x*2+1].lazy+=t[x].lazy)%=p;(t[x*2+1].val+=t[x].lazy*(t[x*2+1].r-t[x*2+1].l+1))%=p;t[x].lazy=0;}}void change(int x,int l,int r,int num){if(t[x].l==l&&t[x].r==r){(t[x].val+=num*(t[x].r-t[x].l+1))%=p;(t[x].lazy+=num)%=p;return;}downdata(x);int mid=(t[x].l+t[x].r)>>1;if(r<=mid) change(x*2,l,r,num);else if(l>mid) change(x*2+1,l,r,num);else change(x*2,l,mid,num),change(x*2+1,mid+1,r,num);t[x].val=(t[x*2].val+t[x*2+1].val)%p;}int find(int x,int l,int r){if(t[x].l==l&&t[x].r==r)return t[x].val;downdata(x);int mid=(t[x].l+t[x].r)>>1;if(r<=mid) return find(x*2,l,r);else if(l>mid) return find(x*2+1,l,r);else return (find(x*2,l,mid)+find(x*2+1,mid+1,r))%p;    }
}LT;//线段树
struct edge_node{int to,next;
}a[N*2];
void addl(int x,int y)
{a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;
}
void dfs1(int x,int fa)//第一遍预处理
{siz[x]=1;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa) continue;dep[y]=dep[x]+1;f[y]=x;dfs1(y,x);siz[x]+=siz[y];if(siz[y]>siz[son[x]])son[x]=y;}
}
void dfs2(int x,int fa)//第二遍预处理
{seg[x]=++cnt;id[cnt]=x;if(son[x]){top[son[x]]=top[x];dfs2(son[x],x);}for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa||y==son[x]) continue;top[y]=y;dfs2(y,x);}
}
void path_change(int x,int y,int z)//路径修改
{while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]]) swap(x,y);//哪个深度大跳哪个LT.change(1,seg[top[x]],seg[x],z);//路径修改x=f[top[x]];//跳}if(dep[x]>dep[y]) swap(x,y);LT.change(1,seg[x],seg[y],z);return;
}
int path_ask(int x,int y)//路径查询—同上
{int ans=0;while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]]) swap(x,y);(ans+=LT.find(1,seg[top[x]],seg[x]))%=p;x=f[top[x]];}if(dep[x]>dep[y]) swap(x,y);(ans+=LT.find(1,seg[x],seg[y]))%=p;return ans;
}
int main()
{scanf("%d%d%d%d",&n,&m,&s,&p);for(int i=1;i<=n;i++)scanf("%d",&pw[i]);for(int i=1;i<n;i++){int x,y;scanf("%d%d",&x,&y);addl(x,y);addl(y,x);}dfs1(s,0);top[s]=s;dfs2(s,0);LT.build(1,1,n);for(int i=1;i<=m;i++){int t,x,y,z;scanf("%d%d",&t,&x);if(t==1){scanf("%d%d",&y,&z);path_change(x,y,z);}if(t==2){scanf("%d",&y);printf("%d\n",path_ask(x,y));}if(t==3){scanf("%d",&z);LT.change(1,seg[x],seg[x]+siz[x]-1,z);}if(t==4){printf("%d\n",LT.find(1,seg[x],seg[x]+siz[x]-1));}}
}

Part 5:练习题

luogu3870−[TJOI2009]luogu3870-[TJOI2009]luogu3870[TJOI2009]开关【分块】

luogu4008−[NOI2003]luogu4008-[NOI2003]luogu4008[NOI2003]文本编辑器【分块】

luogu2634−[luogu2634-[luogu2634[国家集训队]]]聪聪可可【点分治】

luogu4178−Treeluogu4178-Treeluogu4178Tree【点分治】

luogu3714−[BJOI2017]luogu3714-[BJOI2017]luogu3714[BJOI2017]树的难题【点分治】

luogu3345−[ZJOI2015]​luogu3345-[ZJOI2015]​luogu3345[ZJOI2015]幻想乡战略游戏【点分治】

luogu1503−​luogu1503-​luogu1503鬼子进村【Treap​Treap​Treap

luogu1533−luogu1533-luogu1533可怜的狗狗【Treap​Treap​Treap

luogu3313−[SDOI2014]luogu3313-[SDOI2014]luogu3313[SDOI2014]旅行【主席树,,,树链剖分】

luogu2486−[SDOI2011]​luogu2486-[SDOI2011]​luogu2486[SDOI2011]染色【树链剖分】

luogu2146−[NOI2015]luogu2146-[NOI2015]luogu2146[NOI2015]软件包管理器【树链剖分】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/321680.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

33、JAVA_WEB开发基础之会话机制

会话是什么 一个客户端浏览器与web服务器之间连续发生的一系列请求和响应过程就是会话&#xff0c;这些过程中产生的一系列信息就是会话信息&#xff0c;会话机制就是用于维护这些信息一致性的一种技术。通俗的说就是&#xff0c;一个A账号访问服务器&#xff0c;进行多次交互…

35、JAVA_WEB开发基础之过滤器

是什么 过滤器javaweb的一个重要组件&#xff0c;一种规范&#xff0c;可以对发送到serlvet的请求进行拦截和响应进行过滤。实际开发中可以使用过滤器来对访问服务器的请求进行过滤&#xff0c;以提高安全性 过滤器的原理 可以配置过滤器对指定的请求进行过滤&#xff0c;就…

2、安装和连接mysql

安装mysql 1、官网下载mysql 下载网址&#xff1a;https://www.mysql.com/ 2、解压并配置mysql 解压下载的&#xff08;前提下载的zip版本的mysql&#xff09;mysql安装包&#xff0c;放到指定磁盘 配置环境变量&#xff1a;将mysql下的bin目录的全路径名配置到环境变量的p…

6、mysql中字段

对数据表的操作是比较重要的&#xff0c;在实际开发中&#xff0c;日常做的主要工作就是对数据表的操作 对数据表的操作分为两大部分&#xff1a;操作数据表的结构、操作数据表中的数据 组成数据表的基本单元就是字段&#xff0c;所以&#xff0c;接下来先介绍一下mysql中的字…

在Linux环境下使用Apache部署ASP.NET Core

在前几篇文章中我们一起探讨了如何在Linux环境中安装ASP.NET Core运行时环境及将ASP.NET Core项目部署在Jexus中&#xff0c;这篇文章中我们将探讨如何将ASP.NET Core部署于Apache&#xff08;阿帕奇&#xff09;中。 很幸运能够和大家一起学习和探讨ASP.NET Core本文章运行…

傲娇码农的自我修养

一个热爱自己职业的人一定会对自己的工作充满自豪感&#xff0c;同样&#xff0c;也应该对自己的工作充满热情和自信。对自己的专业能力骄傲而不自满。身为一个码农&#xff0c;如果你热爱自己的工作&#xff0c;我想&#xff0c;你很有可能也是一位傲娇码农。在我的眼里&#…

中国到底有多少个.NET 程序员?都在哪个城市写代码?

中国到底多少个.NET 程序员&#xff0c;对于这个问题&#xff0c;似乎没有一个准确的答案&#xff0c;而且最近很多使用.NET 开发技术的老板在抱怨找不到.NET 开发人员&#xff0c;所以我想基于我的公众号粉丝数据给大家分享下中国的.NET程序员到底有多少&#xff0c;他们也都是…

微软西雅图总部DevOps交流总结

本文转自Study4台湾社区。Study4台湾社区&#xff0c;成立于2011/9/25&#xff0c;希望藉由社群推广的力量&#xff0c;让台下的朋友听到来自不同县市的大师讲课&#xff0c;也让台上年轻一辈的技术传教士能不断的琢磨并且追上大师这是一个社群&#xff0c;社区希望透过分享&am…

C# 快速高效率复制对象另一种方式 表达式树

一、需求在代码中经常会遇到需要把对象复制一遍&#xff0c;或者把属性名相同的值复制一遍。比如&#xff1a;public class Student{public int Id { get; set; }public string Name { get; set; } public int Age { get; set; } }public class StudentSecond{public int Id { …

用C# (.NET Core) 实现抽象工厂设计模式

本文的概念性内容来自深入浅出设计模式一书.上一篇文章讲了简单工厂和工厂方法设计模式 使用的是披萨店的例子. 文将继续使用这个例子, 这里要用到抽象工厂.披萨店的需求变更现在披萨店在各地授权了很多连锁分店, 但是有的分店偷工减料, 使用劣质原料代替标准原料.披萨店老板现…

14、mysql中事务的应用

是什么 事务是一种保护连续操作同时满足&#xff08;实现&#xff09;的一种机制&#xff0c;用来保护数据的完整性&#xff0c;只适用于数据操作&#xff0c;不适用于结构操作&#xff0c;只有 innodb引擎的表具有事务安全的机制。就是说&#xff0c;在一个事务中做一系列的…

Summer Training day4 欧拉降幂

Input2 Output2Hint 1. For N 2, S(1) S(2) 1.2. The input file consists of multiple test cases. Sample Input2 Sample Output2这道题的公式非常简单&#xff0c;就是求2^(N-1) %1e97 由于N实在是太大了&#xff0c;不能直接求快速幂&#xff0c;考虑到2^x % MOD是有循…

Project Honolulu 正式版发布为 Windows Admin Center

微软今天正式发布了 Project Honolulu 的正式版&#xff0c;其正式的名称为 Windows Admin Center&#xff0c;gOxiA 之前一直在这个 TAP 中&#xff0c;从 1711 到 1804 可以看出微软现在的开发速度之快&#xff0c;从测试情况看 WAC 质量非常高。正如之前日志说讲 Windows Ad…

使用C# (.NET Core) 实现命令设计模式 (Command Pattern)

本文的概念内容来自深入浅出设计模式一书.项目需求有这样一个可编程的新型遥控器, 它有7个可编程插槽, 每个插槽可连接不同的家用电器设备. 每个插槽对应两个按钮: 开, 关(ON, OFF). 此外还有一个全局的取消按钮(UNDO).现在客户想使用这个遥控器来控制不同厂家的家用电器, 例如…

Summer Training day4上帝与集合的正确用法 欧拉函数+降幂公式

这个题的指数太大了&#xff0c;因此要考虑用降幂公式进行降幂 记f(p) 2^2^2... % p f(p) 2^(2^2^2...%phi(p) phi(p)) % p 2^(f(phi(p)) phi(p)) % p 到这里我们得到了一个递推方程&#xff0c;边界f(1) 0 #include <iostream> #include <cstdio> #inclu…

把旧系统迁移到.Net Core 2.0 日记(2) - 依赖注入/日志NLog

Net Core 大量使用依赖注入(Dependency Inject), 打个比方,我们常用的日志组件有Log4Net,NLog等等.如果我们要随时替换日志组件,那么代码中就不能直接引用某个组件的内容,也不能直接New 某个组件.而是应该定义一组接口, 然后包装各个组件,实现这个接口. Net Core 自带组件容器,…

开源纯C#工控网关+组态软件(九)定制Visual Studio

一、 引子因为最近很忙&#xff08;lan&#xff09;&#xff0c;很久没发博了。不少朋友对那个右键弹出菜单和连线的功能很感兴趣&#xff0c;因为VS本身是不包含这种功能的。大家想这是什么鬼&#xff0c;怎么我的设计器没有&#xff0c;其实这是一个微软黑科技&#xff0c;…

19、mysql中定时器的创建和使用

mysql中可以使用定时器&#xff0c;用来进行计划的调度&#xff0c;在mysql中定时器通过事件的形式存在&#xff0c;接下来介绍一下定时器的使用 创建定时器 CREATE EVENT IF NOT EXISTS 计划名-- 计划频率和开启计划时间或者是计划执行的时间-- 前一个可以实现持续的计划调度…

使用C#实现适配器模式 (Adapter Pattern) 和外观模式 (Facade Pattern)

本文的概念内容来自深入浅出设计模式一书现实世界中的适配器(模式)我带着一个国标插头的笔记本电脑, 来到欧洲, 想插入到欧洲标准的墙壁插座里面, 就需要用中间这个电源适配器.面向对象的适配器你有个老系统, 现在来了个新供应商的类, 但是它们的接口不同, 如何使用这个新供应商…

在 .NET Core 中使用 DiagnosticSource 记录跟踪信息

前言最新一直在忙着项目上的事情&#xff0c;很久没有写博客了&#xff0c;在这里对关注我的粉丝们说声抱歉&#xff0c;后面我可能更多的分享我们在微服务落地的过程中的一些经验。那么今天给大家讲一下在 .NET Core 2 中引入的全新 DiagnosticSource 事件机制&#xff0c;为什…