Solution Set - CDQ分治&整体二分
A[洛谷P2163].给定平面上若干个点,多次询问给定矩形内的点数。
B[洛谷P3810].给定若干个三元组,对所有\(k\),求这样三元组的个数:恰有\(k\)个三元组,满足其每个分量都不超过它的相应分量。
C[洛谷P3157].给定一个序列,从中依次删去某些元素,求每次删除前逆序对数目。
D[CF762E/CF1045G].给定若干三元组\((x_i,r_i,f_i)\),求满足\(|x_i-x_j|\le \min(r_i,r_j)\)且\(|f_i-f_j|\le k\)的无序对\((i,j)\)数目。
E[CF641E].维护一个带时间戳的multiset,要求在某时刻插入/删除某个数,询问某个数的个数。
F[洛谷P4390].维护一个平面,单点修改,矩形查询。
G[洛谷P4093].给定一个序列,可能发生若干种修改中的至多一种,修改形如将某个数改为某个值。求在所有情况下都是单调不减子序列的最长子序列。
H[洛谷P2487].给定两个序列,求一个最长的下标序列,使得其在两个序列都单调递减。在所有这样的序列中等概率取一个,求包含某个位置的概率。
I[洛谷P4027].给定两种金券在\(n\)天内的单价及初始钱数,每一天可以将所有的钱兑换两种金券(两种金券的比例给定),或者卖掉所有金券。求\(n\)天后的最大钱数。
J[洛谷P3206].给定一棵树,边有权,给定若干次修改某条边的权,求每次修改后的最小生成树边权和。
K[CF848C].给定一个序列,单点修改,询问某段区间中所有数最后一次出现位置减去第一次出现位置的值的和。
L[洛谷P6406].给定一个序列,求所有区间最小值,最大值和长度之积的和。
M[LOJ#2880].给定平面上若干个横、纵坐标互不相同的点,求这样的矩形数目:其左下角,右上角是给定点,内部没有给定点。
N[洛谷P3332].维护若干个可重集,要求在一段连续集合中加入一个数,询问一段连续集合的并集中的第\(k\)大值。
O[SPOJ-METEORS].一个环,每个点有一个类型,每个类型有一个目标,现在给环上若干区间加某个值,问每个类型的点权值和在那一次操作后达到目标。
P[洛谷P7424].给定若干区间,每个区间有一个目标,现在给某些位置加一,问每个区间内权值和何时达到目标。
Q[洛谷P2617].给定一个序列,单点修改,询问区间第\(k\)小值。
A离线询问,用二维前缀和转化,然后按照横坐标顺序加点和处理询问。
B是CDQ分治模板,用树状数组维护。
C将时间看作一位,还是模板。也可以用分块。
D先按照\(r\)排序,然后用双指针处理\(x\),用树状数组处理\(f\)。
E直接用CDQ分治,开桶统计即可。
F用CDQ分治,中间使用A题思路。
G考虑DP,记录每个位置原始值\(a_i\),最小可能值\(b_i\),最大可能值\(c_i\),则\(dp_i=max\{dp_j\}+1\),其中\(j \le i,a_j \le b_i,c_j \le a_i\),用CDQ分治优化转移即可。
H和G类似。
I列出转移方程(很容易)后斜率优化,也用CDQ分治维护。
J对操作序列CDQ分治,处理每段序列时,将不会影响的边先处理——加入某些必选入最小生成树的边,然后缩点。用一个按秩合并的可撤销并查集维护。
K树套树,转化为对满足\(l \le i \le r,nxt_i \le r\)的所有\(i\)求\(nxt_i - i\)之和。
L区间分治。枚举最小值的位置,假设在左边,记录右边最长扩展位置和每个位置的最大值,用两个堆维护。可以参考代码中的一句注释。
M用CDQ分治,先按横坐标排序,中间两边按纵坐标排序,维护两个单调栈。对右边每个点,有一段可能的纵坐标区间,二分求其在左边单调栈中的点数目。
N,O,P,Q都可以算作整体二分模板,只有Q需要注意修改方式是先删除再增加。
点击查看A题代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5,M=1e7+10;
int n,m,c[M],cnt,ans[N];
struct point{int x,y,no,ans;}a[N],q[N<<2];
bool operator <(const point &a,const point &b){
if(a.x==b.x)return a.y<b.y;
return a.x<b.x;
}
void add(int x){for(;x<=M-5;x+=x&-x)++c[x];}
int ask(int x){int res=0;for(;x;x-=x&-x)res+=c[x];return res;}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y);
for(int i=1,x,y,z,w;i<=m;i++){
scanf("%d%d%d%d",&x,&y,&z,&w);
q[++cnt].x=x-1;q[cnt].y=y-1;q[cnt].no=i;q[cnt].ans=0;
q[++cnt].x=x-1;q[cnt].y=w;q[cnt].no=-i;q[cnt].ans=0;
q[++cnt].x=z;q[cnt].y=y-1;q[cnt].no=-i;q[cnt].ans=0;
q[++cnt].x=z;q[cnt].y=w;q[cnt].no=i;q[cnt].ans=0;
}
sort(a+1,a+n+1);a[n+1].x=a[n+1].y=M-5;
sort(q+1,q+4*m+1);
int pos=0;
for(int i=1;i<=n+1;i++){
while(q[pos+1].x<a[i].x&&pos<cnt){
++pos;
q[pos].ans=ask(q[pos].y+2);
}
add(a[i].y+2);
}
for(int i=1;i<=4*m;i++){
if(q[i].no>0)ans[q[i].no]+=q[i].ans;
else ans[-q[i].no]-=q[i].ans;
}
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}
点击查看B题代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,k,cnt[N],ans[N];
struct point{int x,y,z,res,cnt;}a[N],x[N];
bool cmp1(point a,point b){
if(a.x!=b.x)return a.x<b.x;
if(a.y!=b.y)return a.y<b.y;
return a.z<b.z;
}
bool cmp2(point a,point b){
if(a.y!=b.y)return a.y<b.y;
return a.z<b.z;
}
struct BIT{
int c[N+5];
void modify(int x,int v){for(;x<=N;x+=x&-x)c[x]+=v;}
int query(int x){int res=0;for(;x;x-=x&-x)res+=c[x];return res;}
}b;
void CDQ(int l,int r){
if(l==r)return;
int mid=l+r>>1,j=l;
CDQ(l,mid);CDQ(mid+1,r);
sort(a+l,a+mid+1,cmp2);
sort(a+mid+1,a+r+1,cmp2);
for(int i=mid+1;i<=r;i++){
while(j<=mid&&a[j].y<=a[i].y)
b.modify(a[j++].z,a[j].cnt);
a[i].res+=b.query(a[i].z);
}
for(int i=l;i<j;i++)b.modify(a[i].z,-a[i].cnt);
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
a[i].res=a[i].cnt=0;x[i]=a[i];
}
sort(x+1,x+n+1,cmp1);
a[m=1]=x[1];a[1].cnt=1;
for(int i=2;i<=n;i++){
if(x[i].x!=a[m].x||x[i].y!=a[m].y||x[i].z!=a[m].z)a[++m]=x[i];
++a[m].cnt;
}
CDQ(1,m);
for(int i=1;i<=m;i++)ans[a[i].res+a[i].cnt]+=a[i].cnt;
for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
return 0;
}
点击查看C题代码
//CDQ分治
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m;long long ans[N];
struct point{int x,y,z;}a[N];
bool cmp1(point a,point b){return a.z<b.z;}
bool cmp2(point a,point b){return a.x<b.x;}
struct BIT{
int c[N];
void modify(int x,int v){for(;x<=n;x+=x&-x)c[x]+=v;}
int query(int x){int res=0;for(;x;x-=x&-x)res+=c[x];return res;}
}b;
void CDQ(int l,int r){
if(l==r)return;
int mid=l+r>>1,i,j;
CDQ(l,mid);CDQ(mid+1,r);
sort(a+l,a+mid+1,cmp2);
sort(a+mid+1,a+r+1,cmp2);
for(i=l,j=mid+1;i<=mid;i++){
while(j<=r&&a[j].x<a[i].x)
b.modify(a[j++].y,1);
ans[a[i].z]+=b.query(a[i].y);
}
for(i=mid+1;i<j;i++)b.modify(a[i].y,-1);
for(i=mid,j=r;i>=l;i--){
while(j>=mid+1&&a[j].x>a[i].x)
b.modify(a[j--].y,1);
ans[a[i].z]+=b.query(n)-b.query(a[i].y);
}
for(i=r;i>j;i--)b.modify(a[i].y,-1);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,x;i<=n;i++)scanf("%d",&x),a[x].y=i,a[i].x=n-i+1;
for(int i=1,x;i<=m;i++)scanf("%d",&x),a[x].z=i;
for(int i=1,j=m;i<=n;i++)if(!a[i].z)a[i].z=++j;
sort(a+1,a+n+1,cmp1);
CDQ(1,n);
for(int i=n;i>=1;i--)ans[i]+=ans[i+1];
for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
return 0;
}
//分块
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5,B=500;
int n,m,a[N],p[N],b[N],f[N],t[N],c[N][B];ll cnt,ans[N];
void add(int x,int p){for(;x<=n;x+=x&-x)++c[x][p];}
int ask(int x,int p){int res=0;for(;x;x-=x&-x)res+=c[x][p];return res;}
void modify(int x){
int id=(p[x]-1)/B+1;
for(int i=1;i<id;i++)cnt+=ask(n,i)-ask(x,i);
for(int i=(id-1)*B+1;i<p[x];i++)if(t[i]>x)++cnt;
for(int i=p[x]+1;i<=id*B;i++)if(t[i]!=0&&t[i]<x)++cnt;
for(int i=id+1;i<=n/B+1;i++)cnt+=ask(x,i);
add(x,id);t[p[x]]=x;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",a+i),p[a[i]]=i;
for(int i=1;i<=m;i++)scanf("%d",b+i),f[b[i]]=1;
for(int i=1;i<=n;i++)if(!f[i])modify(i);
for(int i=m;i>=1;i--)modify(b[i]),ans[i]=cnt;
for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
return 0;
}
点击查看D题代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,k,y[N],m;long long ans;
struct node{int x,r,f;}a[N];
bool cmp1(node a,node b){return a.r<b.r;}
bool cmp2(node a,node b){return a.x<b.x;}
bool cmp3(node a,node b){return a.x+a.r<b.x+b.r;}
bool cmp4(node a,node b){return a.x-a.r<b.x-b.r;}
struct BIT{
int c[N+5],t[N+5],tim;
void modify(int x,int v){
x=lower_bound(y+1,y+m+1,x)-y;
for(;x<=N;x+=x&-x)
if(t[x]!=tim)c[x]=v,t[x]=tim;
else c[x]+=v;
}
int query(int x){
x=upper_bound(y+1,y+m+1,x)-y-1;
int res=0;
for(;x>0;x-=x&-x)if(t[x]==tim)res+=c[x];
return res;
}
}b;
void CDQ(int l,int r){
if(l==r)return;
int mid=l+r>>1;
CDQ(l,mid);CDQ(mid+1,r);
sort(a+mid+1,a+r+1,cmp2);
sort(a+l,a+mid+1,cmp3);
for(int i=l,j=mid+1;i<=mid;i++){
while(j<=r&&a[j].x<=a[i].x+a[i].r)
b.modify(a[j++].f,1);
ans+=b.query(a[i].f+k)-b.query(a[i].f-k-1);
}++b.tim;
sort(a+l,a+mid+1,cmp4);
for(int i=l,j=mid+1;i<=mid;i++){
while(j<=r&&a[j].x<a[i].x-a[i].r)
b.modify(a[j++].f,1);
ans-=b.query(a[i].f+k)-b.query(a[i].f-k-1);
}++b.tim;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&a[i].x,&a[i].r,&a[i].f),y[i]=a[i].f;
sort(a+1,a+n+1,cmp1);
sort(y+1,y+n+1);m=unique(y+1,y+n+1)-y-1;
CDQ(1,n);
printf("%lld\n",ans);
return 0;
}
点击查看E题代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,x[N],ans[N],cnt[N];
struct node{int op,t,x,id;}a[N];
bool cmp2(node a,node b){return a.t!=b.t?a.t<b.t:a.op<b.op;}
bool cmp3(node a,node b){return a.id<b.id;}
void CDQ(int l,int r){
if(l==r)return;
int mid=l+r>>1,j=l;
CDQ(l,mid);CDQ(mid+1,r);
for(int i=mid+1;i<=r;i++){
while(j<=mid&&a[j].t<=a[i].t){
if(a[j].op==1)cnt[a[j].x]++;
if(a[j].op==2)cnt[a[j].x]--;
j++;
}
if(a[i].op==3)ans[a[i].id]+=cnt[a[i].x];
}
for(int i=l;i<j;i++)cnt[a[i].x]=0;
sort(a+l,a+r+1,cmp2);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&a[i].op,&a[i].t,&a[i].x);
x[i]=a[i].x;a[i].id=i;
}
sort(x+1,x+n+1);int m=unique(x+1,x+n+1)-x-1;
for(int i=1;i<=n;i++)a[i].x=lower_bound(x+1,x+n+1,a[i].x)-x;
CDQ(1,n);sort(a+1,a+n+1,cmp3);
for(int i=1;i<=n;i++)if(a[i].op==3)printf("%d\n",ans[i]);
return 0;
}
点击查看F题代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5,M=2e6+5;
int s,w,n;ll ans[N];
struct node{int op,a,b,c,d;}a[N];
struct point{int x,y,id;ll ans;}b[N],q[N<<2];
bool operator <(const point &a,const point &b){
if(a.x==b.x)return a.y<b.y;
return a.x<b.x;
}
struct BIT{
ll c[M+5];int t[M+5],tim;
void modify(int x,int v){
for(;x<=M;x+=x&-x)
if(t[x]!=tim)c[x]=v,t[x]=tim;
else c[x]+=v;
}
int query(int x){
ll res=0;
for(;x>0;x-=x&-x)if(t[x]==tim)res+=c[x];
return res;
}
}B;
void CDQ(int l,int r){
if(l==r)return;
int mid=l+r>>1;
CDQ(l,mid);CDQ(mid+1,r);
int m=0,k=0;
for(int i=l;i<=mid;i++)if(a[i].op==1){
b[++m].x=a[i].a;b[m].y=a[i].b;
b[m].id=a[i].c;
}b[m+1].x=M;
for(int i=mid+1;i<=r;i++)if(a[i].op==2){
q[++k].x=a[i].a-1;q[k].y=a[i].b-1;q[k].id=i;q[k].ans=0;
q[++k].x=a[i].a-1;q[k].y=a[i].d;q[k].id=-i;q[k].ans=0;
q[++k].x=a[i].c;q[k].y=a[i].b-1;q[k].id=-i;q[k].ans=0;
q[++k].x=a[i].c;q[k].y=a[i].d;q[k].id=i;q[k].ans=0;
}
sort(b+1,b+m+1);sort(q+1,q+k+1);++B.tim;
for(int i=1,j=1;i<=m+1;i++){
while(q[j].x<b[i].x&&j<=k)
q[j].ans=B.query(q[j].y+2),j++;
B.modify(b[i].y+2,b[i].id);
}
for(int i=1;i<=k;i++){
if(q[i].id>0)ans[q[i].id]+=q[i].ans;
else ans[-q[i].id]-=q[i].ans;
}
}
int main(){
scanf("%d%d",&n,&n);n=0;
while(scanf("%d",&a[++n].op),a[n].op!=3){
if(a[n].op==1)scanf("%d%d%d",&a[n].a,&a[n].b,&a[n].c);
else scanf("%d%d%d%d",&a[n].a,&a[n].b,&a[n].c,&a[n].d);
}--n;
CDQ(1,n);
for(int i=1;i<=n;i++)if(a[i].op==2)printf("%lld\n",ans[i]);
return 0;
}
点击查看G题代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,a[N],mn[N],mx[N],f[N],id[N],ans;
struct BIT{
int c[N+5],t[N+5],tim;
void modify(int x,int v){
for(;x<=N;x+=x&-x)
if(t[x]!=tim)c[x]=v,t[x]=tim;
else c[x]=max(c[x],v);
}
int query(int x){
int res=0;
for(;x>0;x-=x&-x)if(t[x]==tim)res=max(res,c[x]);
return res;
}
}b;
bool cmp1(int i,int j){return a[i]<a[j];}
bool cmp2(int i,int j){return mx[i]<mx[j];}
void CDQ(int l,int r){
if(l==r){f[l]=max(f[l],1);return;}
int mid=l+r>>1;
CDQ(l,mid);
sort(id+l,id+mid+1,cmp2);
sort(id+mid+1,id+r+1,cmp1);
++b.tim;
for(int i=mid+1,j=l;i<=r;i++){
while(j<=mid&&mx[id[j]]<=a[id[i]])
b.modify(a[id[j]],f[id[j]]),j++;
f[id[i]]=max(f[id[i]],b.query(mn[id[i]])+1);
}
sort(id+l,id+r+1);
CDQ(mid+1,r);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",a+i);
mn[i]=mx[i]=a[i];id[i]=i;
}
for(int i=1,x,y;i<=m;i++){
scanf("%d%d",&x,&y);
mn[x]=min(mn[x],y);mx[x]=max(mx[x],y);
}
CDQ(1,n);
for(int i=1;i<=n;i++)ans=max(ans,f[i]);
printf("%d\n",ans);
return 0;
}
点击查看H题代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,h[N],v[N],y[N],id[N];
struct node{int ans;double cnt;}f[N],g[N],ans;
node operator +(const node&a,const node&b){
node c;
if(a.ans==b.ans)c.ans=a.ans,c.cnt=a.cnt+b.cnt;
else if(a.ans>b.ans)c=a;
else c=b;
return c;
}
struct BIT{
node c[N+5];
int t[N+5],tim;
void modify(int x,node v){
for(;x<=N;x+=x&-x)
if(t[x]!=tim)c[x]=v,t[x]=tim;
else c[x]=c[x]+v;
}
node query(int x){
node res;res.cnt=res.ans=0;
for(;x>0;x-=x&-x)if(t[x]==tim)res=res+c[x];
return res;
}
}B;
bool cmp(int i,int j){return h[i]<h[j];}
void CDQ(int l,int r,node x[]){
if(l==r){x[l]=x[l]+node{1,1};return;}
int mid=l+r>>1;
CDQ(l,mid,x);
sort(id+l,id+mid+1,cmp);
sort(id+mid+1,id+r+1,cmp);
++B.tim;
for(int i=mid+1,j=l;i<=r;i++){
while(j<=mid&&h[id[j]]<=h[id[i]])
B.modify(v[id[j]],x[id[j]]),++j;
node tmp=B.query(v[id[i]]);++tmp.ans;
x[id[i]]=x[id[i]]+tmp;
}
for(int i=l;i<=r;i++)id[i]=i;
CDQ(mid+1,r,x);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",h+i,v+i);id[i]=i;
h[i]=-h[i];v[i]=-v[i];y[i]=v[i];
}
sort(y+1,y+n+1);int m=unique(y+1,y+n+1)-y-1;
for(int i=1;i<=n;i++)v[i]=lower_bound(y+1,y+m+1,v[i])-y;
CDQ(1,n,f);
for(int i=1;i<=n;i++)h[i]=-h[i],v[i]=m+1-v[i];
reverse(h+1,h+n+1);reverse(v+1,v+n+1);
CDQ(1,n,g);
for(int i=1;i<=n;i++)ans=ans+f[i];
printf("%d\n",ans.ans);
for(int i=1;i<=n;i++)
if(f[i].ans+g[n-i+1].ans-1==ans.ans)
printf("%.5lf ",f[i].cnt*g[n-i+1].cnt/ans.cnt);
else printf("0.00000 ");
return 0;
}
点击查看I题代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,s,id[N],q[N],he,ta;
double a[N],b[N],c[N],x[N],y[N],dp[N],ans;
bool cmp1(int i,int j){return x[i]!=x[j]?x[i]<x[j]:y[i]>y[j];}
bool cmp2(int i,int j){return a[i]/b[i]<a[j]/b[j];}
void CDQ(int l,int r){
if(l==r){dp[l]=max(dp[l],dp[l-1]);return;}
int mid=l+r>>1;
CDQ(l,mid);
for(int i=l;i<=mid;i++){
x[i]=dp[i]*c[i]/(a[i]*c[i]+b[i]);
y[i]=dp[i]/(a[i]*c[i]+b[i]);
}
for(int i=l;i<=r;i++)id[i]=i;
sort(id+l,id+mid+1,cmp1);
sort(id+mid+1,id+r+1,cmp2);
he=1;ta=0;
for(int j=l;j<=mid;j++){
if(x[id[j]]==x[q[ta]])continue;
while(he<ta){
int p1=q[ta-1],p2=q[ta];
if((y[p1]-y[p2])/(x[p2]-x[p1])>(y[p1]-y[id[j]])/(x[id[j]]-x[p1]))--ta;
else break;
}
q[++ta]=id[j];
}
for(int i=mid+1;i<=r;i++){
while(he<ta){
int p1=q[he],p2=q[he+1];
if(x[p1]*a[id[i]]+y[p1]*b[id[i]]<x[p2]*a[id[i]]+y[p2]*b[id[i]])++he;
else break;
}
dp[id[i]]=max(dp[id[i]],x[q[he]]*a[id[i]]+y[q[he]]*b[id[i]]);
}
CDQ(mid+1,r);
}
int main(){
scanf("%d%d",&n,&s);
for(int i=1;i<=n;i++)
scanf("%lf%lf%lf",a+i,b+i,c+i);
dp[0]=s;CDQ(1,n);
for(int i=1;i<=n;i++)ans=max(ans,dp[i]);
printf("%.3lf\n",ans);
return 0;
}
点击查看J题代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e4+5,M=5e4+5;
int n,m,q;
struct disjoint_set{
int fa[N],sz[N],st[M][2],top;
void init(){for(int i=1;i<=n;i++)fa[i]=i,sz[i]=1;}
int find(int x){return (fa[x]==x?x:find(fa[x]));}
void Union(int x,int y){
int u=find(x),v=find(y);
if(u==v)return;
if(sz[u]<sz[v])swap(u,v);
sz[u]+=sz[v];fa[v]=u;
st[++top][0]=u;st[top][1]=v;
}
void remove(){
int u=st[top][0],v=st[top][1];--top;
sz[u]-=sz[v];fa[v]=v;
}
void clear(int tim){while(top>tim)remove();}
}S,S1;
struct edge{int u,v;ll w;int mark;}e[M];
bool operator <(const edge&a,const edge&b){return a.w<b.w;}
vector<edge>ve[30],vq,tr;ll res[30];int tim[30];bool f[M];
struct query{int num;ll val,ans;}p[M];
void push_down(int dep){
tr.clear();
for(int i=0;i<ve[dep].size();i++)tr.push_back(ve[dep][i]);
sort(tr.begin(),tr.end());
for(int i=0;i<tr.size();i++){
if(S1.find(tr[i].u)==S1.find(tr[i].v))tr[i].mark=-1;
else S1.Union(tr[i].u,tr[i].v);
}S1.clear(0);res[dep+1]=res[dep];
for(int i=0;i<vq.size();i++)S1.Union(vq[i].u,vq[i].v);vq.clear();
for(int i=0;i<tr.size();i++)
if(tr[i].mark!=-1&&S1.find(tr[i].u)!=S1.find(tr[i].v)){
tr[i].mark=1;S1.Union(tr[i].u,tr[i].v);
S.Union(tr[i].u,tr[i].v);res[dep+1]+=tr[i].w;
}
S1.clear(0);ve[dep+1].clear();
for(int i=0,u,v;i<tr.size();i++)
if(!tr[i].mark&&(u=S.find(tr[i].u))!=(v=S.find(tr[i].v)))
ve[dep+1].push_back({u,v,tr[i].w,0});
}
void CDQ(int l,int r,int dep){
if(l==r){
ve[dep].push_back({S.find(e[p[l].num].u),S.find(e[p[l].num].v),p[l].val,0});
e[p[l].num].w=p[l].val;push_down(dep);
p[l].ans=res[dep+1];S.clear(tim[dep-1]);
return;
}
tim[dep]=S.top;int mid=l+r>>1;
for(int i=l;i<=mid;i++)f[p[i].num]=true;
for(int i=mid+1,id;i<=r;i++)if(!f[id=p[i].num])
ve[dep].push_back({S.find(e[id].u),S.find(e[id].v),e[id].w,0});
for(int i=l;i<=mid;i++)
vq.push_back({S.find(e[p[i].num].u),S.find(e[p[i].num].v),0,0});
push_down(dep);
for(int i=mid+1;i<=r;i++)if(!f[p[i].num])ve[dep].pop_back();
for(int i=l;i<=mid;i++)f[p[i].num]=false;CDQ(l,mid,dep+1);
for(int i=0;i<ve[dep].size();i++)ve[dep][i].mark=0;
for(int i=mid+1;i<=r;i++)f[p[i].num]=true;
for(int i=l,id;i<=mid;i++)if(!f[id=p[i].num])
ve[dep].push_back({S.find(e[id].u),S.find(e[id].v),e[id].w,0});
for(int i=mid+1;i<=r;i++){
f[p[i].num]=0;
vq.push_back({S.find(e[p[i].num].u),S.find(e[p[i].num].v),0,0});
}
push_down(dep);CDQ(mid+1,r,dep+1);
S.clear(tim[dep-1]);
}
int main(){
scanf("%d%d%d",&n,&m,&q);S.init();S1.init();
for(int i=1;i<=m;i++)scanf("%d%d%lld",&e[i].u,&e[i].v,&e[i].w);
for(int i=1;i<=q;i++)scanf("%d%lld",&p[i].num,&p[i].val);
for(int i=1;i<=q;i++){
int id=p[i].num;f[id]=true;
vq.push_back({e[id].u,e[id].v,0,0});
}
for(int i=1;i<=m;i++)if(!f[i])ve[1].push_back(e[i]);
for(int i=1;i<=q;i++)f[p[i].num]=false;
CDQ(1,q,1);
for(int i=1;i<=q;i++)printf("%lld\n",p[i].ans);
return 0;
}
点击查看K题代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,q,a[N],lst[N],nxt[N],now[N];
int root[N],lc[N*100],rc[N*100],tot;ll sum[N*100];
int new_node(){
++tot;
lc[tot]=rc[tot]=0;
return tot;
}
void modify(int p,int l,int r,int x,int v){
if(l==r){sum[p]+=v;return;}
int mid=l+r>>1;
if(x<=mid){
if(!lc[p])lc[p]=new_node();
modify(lc[p],l,mid,x,v);
}
else{
if(!rc[p])rc[p]=new_node();
modify(rc[p],mid+1,r,x,v);
}
sum[p]=sum[lc[p]]+sum[rc[p]];
}
ll query(int p,int l,int r,int L,int R){
if(!p)return 0;
if(l>=L&&r<=R)return sum[p];
int mid=l+r>>1;ll res=0;
if(L<=mid)res+=query(lc[p],l,mid,L,R);
if(R>mid)res+=query(rc[p],mid+1,r,L,R);
return res;
}
void add(int x,int y,int v){for(;x<=n;x+=x&-x)modify(root[x],1,n+1,y,v);}
ll ask(int x,int y){ll res=0;for(;x;x-=x&-x)res+=query(root[x],1,n+1,1,y);return res;}
set<int> S[N];
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)nxt[i]=n+1;
for(int i=1;i<=n;i++){
scanf("%d",a+i);
lst[i]=now[a[i]];
nxt[lst[i]]=i;
now[a[i]]=i;
S[a[i]].insert(i);
}
for(int i=1;i<=n;i++)root[i]=new_node();
for(int i=1;i<=n;i++)add(i,nxt[i],nxt[i]-i);
for(int i=1,op,l,r;i<=q;i++){
scanf("%d%d%d",&op,&l,&r);
if(op==1){
lst[nxt[l]]=lst[l];
nxt[lst[l]]=nxt[l];
if(lst[l]){
add(lst[l],l,-(l-lst[l]));
add(lst[l],nxt[l],nxt[l]-lst[l]);
}
add(l,nxt[l],-(nxt[l]-l));
S[a[l]].erase(S[a[l]].find(l));
auto it=S[r].lower_bound(l);
nxt[l]=(it==S[r].end()?n+1:*it);
lst[l]=(it==S[r].begin()?0:*--it);
nxt[lst[l]]=l;lst[nxt[l]]=l;
add(l,nxt[l],nxt[l]-l);
if(lst[l]){
add(lst[l],nxt[l],-(nxt[l]-lst[l]));
add(lst[l],l,l-lst[l]);
}
S[r].insert(l);a[l]=r;
}
else printf("%lld\n",ask(n,r)-ask(l-1,r));
}
return 0;
}
点击查看L题代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const int N=5e5+5,mod=1e9;
int n;ll a[N];
priority_queue<pll,vector<pll>,greater<pll> > Q1,Q2;
ll solve(int l,int r){
if(l==r)return a[l]*a[l]%mod;
int mid=l+r>>1;
ll ans=(solve(l,mid)+solve(mid+1,r))%mod;
while(!Q1.empty())Q1.pop();while(!Q2.empty())Q2.pop();
ll s1=0,s2=0,s3=0;
//Q1记比mx小的值,Q2记比mx大的值
//s1记Q1的位置和,s2记Q2的元素和,s3记Q2的元素与位置之积的和
ll mn=1e9,mx=0,mx2=0;
for(int i=mid+1,p=mid;i<=r;i++){
mn=min(mn,a[i]);mx=max(mx,a[i]);
while(!Q2.empty()&&Q2.top().first<mx){
ll val=Q2.top().first,pos=Q2.top().second;Q2.pop();
s2=(s2-val+mod)%mod;s3=(s3-val*pos%mod+mod)%mod;
Q1.push(make_pair(val,pos));s1+=pos;
}
while(p>=l&&a[p]>=mn){
mx2=max(mx2,a[p]);
if(mx2<mx)Q1.push(make_pair(mx2,mid-p+1)),s1=(s1+(mid-p+1))%mod;
else{
Q2.push(make_pair(mx2,mid-p+1));
s2=(s2+mx2)%mod;s3=(s3+mx2*(mid-p+1)%mod)%mod;
}
--p;
}
ans=(ans+(1ll*Q1.size()*(i-mid)+s1)%mod*mn%mod*mx%mod+
mn*s3%mod+mn*s2%mod*(i-mid)%mod)%mod;
}
while(!Q1.empty())Q1.pop();while(!Q2.empty())Q2.pop();
mn=1e9;mx=mx2=0;s1=s2=s3=0;
for(int i=mid,p=mid+1;i>=l;i--){
mn=min(mn,a[i]);mx=max(mx,a[i]);
while(!Q2.empty()&&Q2.top().first<=mx){
ll val=Q2.top().first,pos=Q2.top().second;Q2.pop();
s2=(s2-val+mod)%mod;s3=(s3-val*pos%mod+mod)%mod;
Q1.push(make_pair(val,pos));s1+=pos;
}
while(p<=r&&a[p]>mn){
mx2=max(mx2,a[p]);
if(mx2<=mx)Q1.push(make_pair(mx2,p-mid)),s1=(s1+(p-mid))%mod;
else{
Q2.push(make_pair(mx2,p-mid));
s2=(s2+mx2)%mod;s3=(s3+mx2*(p-mid)%mod)%mod;
}
++p;
}
ans=(ans+(1ll*Q1.size()*(mid-i+1)+s1)%mod*mn%mod*mx%mod+
mn*s3%mod+mn*s2%mod*(mid-i+1)%mod)%mod;
}
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lld",a+i);
printf("%lld\n",solve(1,n));
return 0;
}
点击查看M题代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,st[N],q[N];long long ans;
struct point{int x,y;}a[N];
bool cmp1(point a,point b){return a.x<b.x;}
bool cmp2(point a,point b){return a.y<b.y;}
void CDQ(int l,int r){
if(l==r)return;
int mid=l+r>>1;
CDQ(l,mid);CDQ(mid+1,r);
sort(a+l,a+mid+1,cmp2);
sort(a+mid+1,a+r+1,cmp2);
int top=0,he=1,ta=0;
for(int i=mid+1,j=l;i<=r;i++){
while(top&&a[i].x<a[st[top]].x)--top;
int d=a[st[top]].y;st[++top]=i;
while(j<=mid&&a[j].y<a[i].y){
while(he<=ta&&a[q[ta]].x<a[j].x)--ta;
q[++ta]=j;++j;
}
int L=1,R=ta,he=ta+1;
while(L<=R){
int Mid=L+R>>1;
if(a[q[Mid]].y>d)R=Mid-1,he=Mid;
else L=Mid+1;
}
ans+=ta-he+1;
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y);
sort(a+1,a+n+1,cmp1);a[0].x=a[0].y=-1;
CDQ(1,n);
printf("%lld\n",ans);
return 0;
}
点击查看N题代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+5;
int n,m;
struct Query{int op,l,r;ll c;int ans;}a[N];
vector<int> q;
struct SegmentTree{
int lc[N<<3],rc[N<<3],tot;ll sum[N<<3],add[N<<3];
void init(){tot=0;new_node();}
int new_node(){
++tot;
lc[tot]=rc[tot]=sum[tot]=add[tot]=0;
return tot;
}
void push_up(int p){sum[p]=sum[lc[p]]+sum[rc[p]];}
void push_down(int p,int l,int r){
if(!add[p])return;
ll v=add[p];add[p]=0;int mid=l+r>>1;
sum[lc[p]]+=v*(mid-l+1);sum[rc[p]]+=v*(r-mid);
add[lc[p]]+=v;add[rc[p]]+=v;
}
void modify(int p,int l,int r,int L,int R,ll v){
if(!lc[p])lc[p]=new_node();
if(!rc[p])rc[p]=new_node();
push_down(p,l,r);
if(l>=L&&r<=R){
sum[p]+=(r-l+1)*v;add[p]+=v;
return;
}
int mid=l+r>>1;
if(L<=mid)modify(lc[p],l,mid,L,R,v);
if(R>mid)modify(rc[p],mid+1,r,L,R,v);
push_up(p);
}
ll query(int p,int l,int r,int L,int R){
if(!p)return 0;
if(!lc[p])lc[p]=new_node();
if(!rc[p])rc[p]=new_node();
push_down(p,l,r);
if(l>=L&&r<=R)return sum[p];
ll res=0;int mid=l+r>>1;
if(L<=mid)res+=query(lc[p],l,mid,L,R);
if(R>mid)res+=query(rc[p],mid+1,r,L,R);
return res;
}
}seg;
void solve(int l,int r,vector<int> q){
if(l==r){
for(auto x:q)a[x].ans=l;
return;
}
int mid=l+r>>1;
vector<int> ql,qr;seg.init();
for(auto x:q){
if(a[x].op==1){
if(a[x].c<=mid)ql.push_back(x);
else{
seg.modify(1,1,n,a[x].l,a[x].r,1);
qr.push_back(x);
}
}
else{
ll tmp=seg.query(1,1,n,a[x].l,a[x].r);
if(tmp>=a[x].c)qr.push_back(x);
else{a[x].c-=tmp;ql.push_back(x);}
}
}
solve(l,mid,ql);solve(mid+1,r,qr);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d%lld",&a[i].op,&a[i].l,&a[i].r,&a[i].c);
if(a[i].op==1)a[i].c+=n+1;q.push_back(i);
}
solve(1,2*n+1,q);
for(auto x:q)if(a[x].op==2)printf("%d\n",a[x].ans-n-1);
return 0;
}
点击查看O题代码
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=3e5+5;
int n,m,k,ans[N];ull p[N];
struct node{int l,r;ull x;}a[N];
vector<int> q,pos[N];
struct BIT{
ull c[N+5];int t[N+5],tim;
void modify(int x,ull v){
for(;x<=m;x+=x&-x)
if(t[x]!=tim)c[x]=v,t[x]=tim;
else c[x]+=v;
}
ull query(int x){
ull res=0;
for(;x>0;x-=x&-x)if(t[x]==tim)res+=c[x];
return res;
}
}B;
void solve(int l,int r,vector<int> q){
if(l==r){
for(auto x:q)ans[x]=l;
return;
}
int mid=l+r>>1;
vector<int> ql,qr;B.tim++;
for(int i=l;i<=mid;i++){
if(a[i].l<=a[i].r)B.modify(a[i].l,a[i].x),B.modify(a[i].r+1,-a[i].x);
else B.modify(1,a[i].x),B.modify(a[i].r+1,-a[i].x),B.modify(a[i].l,a[i].x);
}
for(auto x:q){
ull tmp=0;
for(auto y:pos[x])tmp+=B.query(y);
if(tmp>=p[x])ql.push_back(x);
else{p[x]-=tmp;qr.push_back(x);}
}
solve(l,mid,ql);solve(mid+1,r,qr);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,x;i<=m;i++){scanf("%d",&x);pos[x].push_back(i);}
for(int i=1;i<=n;i++){scanf("%d",p+i);q.push_back(i);ans[i]=-1;}
scanf("%d",&k);
for(int i=1;i<=k;i++)
scanf("%d%d%llu",&a[i].l,&a[i].r,&a[i].x);
a[k+1].l=a[k+1].r=1;a[k+1].x=0;
solve(1,k+1,q);
for(auto x:q){
if(ans[x]!=k+1)printf("%d\n",ans[x]);
else puts("NIE");
}
return 0;
}
点击查看P题代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,b[N],ans[N];
struct wood{int l,r,s;}a[N];
vector<int> q;
struct BIT{
int c[N+5],t[N+5],tim;
void modify(int x,int v){
for(;x<=N;x+=x&-x)
if(t[x]!=tim)c[x]=v,t[x]=tim;
else c[x]+=v;
}
int query(int x){
int res=0;
for(;x>0;x-=x&-x)if(t[x]==tim)res+=c[x];
return res;
}
}B;
void solve(int l,int r,vector<int> q){
if(l==r){ans[l]=q.size();return;}
int mid=l+r>>1;
vector<int> ql,qr;
++B.tim;
for(int i=l;i<=mid;i++)B.modify(b[i],1);
for(auto x:q){
int y=B.query(a[x].r)-B.query(a[x].l-1);
if(y>=a[x].s)ql.push_back(x);
else{a[x].s-=y;qr.push_back(x);}
}
solve(l,mid,ql);solve(mid+1,r,qr);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].s);
q.push_back(i);
}
for(int i=1;i<=m;i++)scanf("%d",b+i);
b[m+1]=0;solve(1,m+1,q);
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}
点击查看Q题代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,m,b[N],r[N],k;char ch;
struct Query{int op,l,r,v,ans;}a[N];
vector<int> q;
struct BIT{
int c[N+5],t[N+5],tim;
void modify(int x,int v){
for(;x<=N;x+=x&-x)
if(t[x]!=tim)c[x]=v,t[x]=tim;
else c[x]+=v;
}
int query(int x){
int res=0;
for(;x>0;x-=x&-x)if(t[x]==tim)res+=c[x];
return res;
}
}B;
void solve(int l,int r,vector<int> q){
if(l==r){
for(auto x:q)a[x].ans=l;
return;
}
int mid=l+r>>1;
vector<int> ql,qr;
B.tim++;
for(auto x:q){
if(a[x].op==1){
if(a[x].v<=mid){
B.modify(a[x].l,a[x].r);
ql.push_back(x);
}
else qr.push_back(x);
}
else{
int y=B.query(a[x].r)-B.query(a[x].l-1);
if(y>=a[x].v)ql.push_back(x);
else{a[x].v-=y;qr.push_back(x);}
}
}
solve(l,mid,ql);solve(mid+1,r,qr);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",b+i);
a[i].op=1;a[i].l=i;a[i].r=1;a[i].v=b[i];
q.push_back(i);r[++k]=b[i];
}
int c=n;
for(int i=1;i<=m;i++){
while(ch=getchar(),ch!='Q'&&ch!='C');
if(ch=='Q'){
a[++c].op=2;
scanf("%d%d%d",&a[c].l,&a[c].r,&a[c].v);
}
else{
int x,y;
scanf("%d%d",&x,&y);r[++k]=y;
a[++c].op=1;a[c].l=x;a[c].r=-1;a[c].v=b[x];
a[++c].op=1;a[c].l=x;a[c].r=1;a[c].v=b[x]=y;
}
}
for(int i=n+1;i<=c;i++)q.push_back(i);
sort(r+1,r+k+1);k=unique(r+1,r+k+1)-r-1;
for(int i=1;i<=c;i++)if(a[i].op==1)
a[i].v=lower_bound(r+1,r+k+1,a[i].v)-r;
solve(1,k,q);
for(auto x:q)if(a[x].op==2)printf("%d\n",r[a[x].ans]);
return 0;
}
Solution Set - CDQ分治&整体二分的更多相关文章
- 一篇自己都看不懂的CDQ分治&整体二分学习笔记
作为一个永不咕咕咕的博主,我来更笔记辣qaq CDQ分治 CDQ分治的思想还是比较简单的.它的基本流程是: \(1.\)将所有修改操作和查询操作按照时间顺序并在一起,形成一段序列.显然,会影响查询操作 ...
- Cdq分治整体二分学习记录
这点东西前前后后拖了好几个星期才学会……还是自己太菜啊. Cdq分治的思想是:把问题序列分割成左右两个,先单独处理左边,再处理左边对右边的影响,再单独处理右边.这样可以消去数据结构上的一个log,降低 ...
- [学习笔记] CDQ分治&整体二分
突然诈尸.png 这两个东西好像都是离线骗分大法... 不过其实这两个东西并不是一样的... 虽然代码长得比较像 CDQ分治 基本思想 其实CDQ分治的基本思想挺简单的... 大概思路就是长这样的: ...
- 算法笔记--CDQ分治 && 整体二分
参考:https://www.luogu.org/blog/Owencodeisking/post-xue-xi-bi-ji-cdq-fen-zhi-hu-zheng-ti-er-fen 前置技能:树 ...
- CDQ分治&整体二分学习个人小结
目录 小结 CDQ分治 二维LIS 第一道裸题 bzoj1176 Mokia bzoj3262 陌上花开 bzoj 1790 矩形藏宝地 hdu5126四维偏序 P3157 [CQOI2011]动态逆 ...
- CQD(陈丹琦)分治 & 整体二分——专题小结
整体二分和CDQ分治 有一些问题很多时间都坑在斜率和凸壳上了么--感觉斜率和凸壳各种搞不懂-- 整体二分 整体二分的资料好像不是很多,我在网上找到了一篇不错的资料: 整体二分是个很神的东西 ...
- CDQ分治 & 整体分治
Part 1:CDQ分治 CDQ分治讲解博客 可以把CDQ分治理解为类似与归并排序求逆序对个数的一种分治算法(至少我现在是这么想的).先处理完左右两边各自对答案的贡献,在处理跨越左右两边的对答案的贡献 ...
- CodeForces - 762E:Radio stations (CDQ分治||排序二分)
In the lattice points of the coordinate line there are n radio stations, the i-th of which is descri ...
- luogu P5473 [NOI2019]I 君的探险 交互 随机 二分 分治 整体二分
LINK:I 君的探险 神仙题! 考虑一个暴力的做法 每次点亮一个点 询问全部点 这样询问次数为 \(\frac{n\cdot (n-1)}{2}\) 可以通过前5个点. 考虑都为A的部分分 发现一个 ...
- UOJ#191. 【集训队互测2016】Unknown 点分治 分治 整体二分 凸包 计算几何
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ191.html 题目传送门 - UOJ191 题意 自行移步集训队论文2016中罗哲正的论文. 题解 自行 ...
随机推荐
- Java内存马1-传统web内存马
1.前置知识 (1)Tomcat Tomcat是一个开源的.轻量级的.用于Java Servlet和JavaServer Pages(JSP)的Web应用程序服务器.它是Apache软件基金会的一个项 ...
- quartus中的时序约束常用方法
quartus中的时序约束常用方法 一.约束操作 quartus中有三种时序约束方法: 1️⃣Timing Setting 2️⃣Wizards/Timing Wizard 3️⃣Assignment ...
- Fastjson反序列化分析
依赖 先研究1.2.24版本的,版本高了就有waf了,不过也能绕,高版本以后再说 <dependency> <groupId>com.alibaba</groupId&g ...
- 开源相机管理库Aravis学习(一)——安装
目录 前言 Aravis简介 依赖关系说明 安装过程 meson安装 aravis源文件下载 构建和安装aravis 视频查看器 安装过程中遇到的问题 meson版本过低 CMake版本过低 缺少GS ...
- 05 CMMI(Capability Maturity Model Integration)【软件过程与管理】
CMMI(Capability Maturity Model Integration) CMMI成熟度等级 执行的:过程不可预测,缺乏控制,反应式的 已管理的:项目描绘过程,而且经常是反应式的 已定义 ...
- #ST表,单调栈#洛谷 5648 Mivik的神力
题目 分析 考虑答案应该是一段单调不下降的序列, 考虑预处理出每个点往后第一个大于这个点的位置, 那么答案应该是左端点到区间内最大的位置以及这个位置到右端点的贡献 那么区间最大的位置可以用ST表做,然 ...
- MindSpore自动微分小技巧
技术背景 基于链式法则的自动微分技术,是大多数深度学习框架中所支持的核心功能,旨在更加快速的进行梯度计算,并且可以绕开符号微分的表达式爆炸问题和手动微分的困难推导问题.本文主要基于MindSpore框 ...
- 如何巧妙应对iOS键盘难题?
前言 写过移动端的同学或多或少都遇到过软键盘带来的各种各样的问题,最典型的就是输入框被软键盘遮挡.fixed元素失效等问题,并且这些问题在iOS上的表现让人难以接受. webview的差异 在移动端上 ...
- Perm 排列计数——Lucas&dfs
思路:这道题给出的公式看明白后即可得出正解,我们可以把他想象成一颗二叉树,任意一个点的任意一个子孙一直除以2后最终都会到达一终点,终点则为以该点为根的子树的最小值. so--我们可以将根节点作为最后终 ...
- 【4】Spring框架的起源
在我们的<Java Spring框架入门教程>中对 Spring 框架进行了十分详尽的介绍和剖析,但在学习 Spring Boot 之前,在这里回顾一下 Spring 是怎么出现的. Sp ...