SPOJ GSS 1-8的解析——一些跟最大子段和有关的数据结构问题的维护技巧

线段树——区间最大子段和问题(SPOJ - GSS1) 问题描述: 给定一段长度为nnn的序列a1,a2,…,ana_1,a_2,\dots,a_na1​,a2​,…,an​(aaa有正亦有负),每次 询问[L,R][L,R][L,R](即aLa_LaL​~aRa_RaR​)范围内的最大字段和,并涉及 单点修改 操作。 【线段树】 维护区间最大子段和: ①定义: 线段树一共要维护444个值,如下:(每个值的含义都是相对于该结点对应区间[l,r][... 阅读详情

题目spoj GSS,但是太卡了,无奈之下水洛谷.

T1:
题目大意:给定一个长度为 n n n的序列,有 m m m次操作,每次操作查询 [ l , r ] [l,r] [l,r]的最大子段和,不可取空序列.
1 ≤ n ≤ 5 ∗ 1 0 4 1\leq n\leq 5*10^4 1≤n≤5∗104, m m m数据范围为 O ( m log ⁡ n ) O(m\log n) O(mlogn)可过.

一道水题,我们可以得知,区间 [ l , r ] [l,r] [l,r]的最大子段和只有三种可能:左半边最大子段和,右半边最大子段和,左半边一定包括最右端的最大子段和加右半边一定包括最左端的最大子段和.

于是我们线段树每个节点就维护四个信息:最大子段和 s u m sum sum,一定包括最左端最大子段和 l s u m lsum lsum,一定包括最右端最大子段和 r s u m rsum rsum,以及区间和 a n s ans ans.

那么我们就可以写出代码:

#include<bits/stdc++.h>
  using namespace std;
typedef long long LL;
const int N=100000;
struct tree{
  int l,r;
  int sum,lsum,rsum,ans;
}tr[N*5];
int n,m,a[N+1];
void build(int L,int R,int k=1){
  tr[k].l=L;tr[k].r=R;
  if (L==R){
    tr[k].ans=tr[k].sum=tr[k].lsum=tr[k].rsum=a[L];
    return;
  }
  int mid=L+R>>1;
  build(L,mid,k<<1);
  build(mid+1,R,k<<1|1);
  tr[k].ans=tr[k<<1].ans+tr[k<<1|1].ans;
  tr[k].lsum=max(tr[k<<1].ans+tr[k<<1|1].lsum,tr[k<<1].lsum);
  tr[k].rsum=max(tr[k<<1|1].ans+tr[k<<1].rsum,tr[k<<1|1].rsum);
  tr[k].sum=max(max(tr[k<<1].sum,tr[k<<1|1].sum),tr[k<<1].rsum+tr[k<<1|1].lsum);
}
struct tree1{
  int ans,sum,lsum,rsum;
};
tree1 query(int L,int R,int k=1){
  if (L==tr[k].l&&R==tr[k].r) return (tree1){tr[k].ans,tr[k].sum,tr[k].lsum,tr[k].rsum};
  int mid=tr[k].l+tr[k].r>>1;
  if (R<=mid) return query(L,R,k<<1);
  else if (L>mid) return query(L,R,k<<1|1);
    else {
      tree1 u=query(L,mid,k<<1),v=query(mid+1,R,k<<1|1),o;
      o.ans=u.ans+v.ans;
      o.lsum=max(u.ans+v.lsum,u.lsum);
      o.rsum=max(v.ans+u.rsum,v.rsum);
      o.sum=max(max(u.sum,v.sum),u.rsum+v.lsum);
      return o;
    }
}
inline void into(){
  scanf("%d",&n);
  for (int i=1;i<=n;i++)
    scanf("%d",&a[i]);
}
inline void work(){
  build(1,n);
}
inline void outo(){
  scanf("%d",&m);
  int x,y;
  for (int i=1;i<=m;i++){
    scanf("%d%d",&x,&y);
    printf("%d\n",query(x,y).sum);
  }
}
int main(){
  into();
  work();
  outo();
  return 0;
}

T2:
与第一题不同的是询问时,若子段中有相同的元素,只能算一个,且可取空序列,其他与GSS1相同.
1 ≤ n , m ≤ 1 0 5 1\leq n,m\leq 10^5 1≤n,m≤105.

这道题如果要做的话,因为题目没有修改操作,只有查询操作,所以我们先给询问区间离线搞下来,按照右端点排序.

排序之后,我们可以给它搞几个修改操作,也就是说,一开始整棵树为空.

之后从 i i i从 1 1 1枚举到 n n n,每一次都进行一个修改,以及回答右端点为 i i i的询问.

那么我们定义一棵线段树,假设当前扫到了第 i i i个点,那么其中第 j j j个叶子节点表示的就是区间 [ j , i ] [j,i] [j,i].

那么我们线段树的非叶子节点其实就没有用了,可以什么信息也不存,只存标记.

我们现在用 m a ma ma表示区间 [ j , i ] [j,i] [j,i]中必须包括右端点 i i i的最大子段和,由于我们不一定要取右端点,所以我们再添加一个 h m a hma hma表示历史最大值(即答案).

那么我们考虑add操作,由于我们要让最大子段和之中相等的数只算一个,那我们设与第 i i i个数相等的数在最后面的位置是 l a s t last last,则我们要修改的区间就是 [ l a s t + 1 , i ] [last+1,i] [last+1,i],所以我们要学会打标记.

所以我们再加两个元素 t a g tag tag和 h t a g htag htag,分别表示增量总和和历史最大增量,其中历史最大增量就是指增量出现过的最大值.

之后在找到了需要增加的区间的时候,我们可以让 t a g tag tag先加上这个数,然后 h t a g htag htag取当前 t a g tag tag和 h t a g htag htag的最大值.

若这个区间是叶子节点,我们则需要将 m a ma ma加上 n u m num num,且 h m a hma hma取 m a ma ma和 h m a hma hma的最大值.

当下传懒标记也就是pushdown的时候,我们要将 k k k的儿子的 t a g tag tag都加上 t r [ k ] . t a g tr[k].tag tr[k].tag, k k k的儿子的 m a ma ma加上 t r [ k ] . t a g tr[k].tag tr[k].tag.

但是当时历史最大时,我们发现这个标记节点 k k k的祖先肯定没有任何标记了,也就是说 t r [ k ] . h t a g tr[k].htag tr[k].htag一定是一段连续的,而且显然的, t r [ k . s o n ] . m a tr[k.son].ma tr[k.son].ma和 t r [ k . s o n ] . t a g tr[k.son].tag tr[k.son].tag肯定也是连续的一段,并且这一段肯定是紧贴 t r [ k ] . h t a g tr[k].htag tr[k].htag的,所以我们可以得出结论:
t r [ k . s o n ] . h m a = m a x ( t r [ k . s o n ] . h m a , t r [ k . s o n ] . m a + t r [ k ] . h t a g ) t r [ k . s o n ] . h t a g = m a x ( t r [ k . s o n ] . h t a g , t r [ k . s o n ] . t a g + t r [ k ] . h t a g ) tr[k.son].hma=max(tr[k.son].hma,tr[k.son].ma+tr[k].htag)\\ tr[k.son].htag=max(tr[k.son].htag,tr[k.son].tag+tr[k].htag) tr[k.son].hma=max(tr[k.son].hma,tr[k.son].ma+tr[k].htag)tr[k.son].htag=max(tr[k.son].htag,tr[k.son].tag+tr[k].htag)

注意 h m a hma hma一定要放在 m a ma ma前更新, h t a g htag htag一定要放在 t a g tag tag前更新.

代码如下:

#include<bits/stdc++.h>
  using namespace std;
typedef long long LL;
const int N=500000;
struct tree{
  int l,r;
  LL ma,hma,tag,htag;
}tr[N*5];
struct question{
  int l,r,id;
}q[N+1];
int n,m,now[N+1],last[N+1],lx[N+1];
LL a[N+1],ans[N+1];
inline void into(){
  scanf("%d",&n);
  for (int i=1;i<=n;i++)
    scanf("%lld",&a[i]);
  scanf("%d",&m);
  for (int i=1;i<=m;i++)
    scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
}
bool cmp(question a,question b){
  return a.r<b.r;
}
void build(int L,int R,int k=1){
  tr[k].l=L;tr[k].r=R;
  if (L==R) return;
  int mid=L+R>>1;
  build(L,mid,k<<1);build(mid+1,R,k<<1|1);
}
void pushdown(int k){
  int ls=k<<1,rs=ls|1;
  tr[ls].htag=max(tr[ls].htag,tr[ls].tag+tr[k].htag);
  tr[rs].htag=max(tr[rs].htag,tr[rs].tag+tr[k].htag);
  tr[ls].hma=max(tr[ls].hma,tr[ls].ma+tr[k].htag);
  tr[rs].hma=max(tr[rs].hma,tr[rs].ma+tr[k].htag);
  tr[ls].tag+=tr[k].tag;tr[rs].tag+=tr[k].tag;
  tr[ls].ma+=tr[k].tag;tr[rs].ma+=tr[k].tag;
  tr[k].tag=tr[k].htag=0LL;
}
void pushup(int k){
  tr[k].ma=max(tr[k<<1].ma,tr[k<<1|1].ma);
  tr[k].hma=max(tr[k<<1].hma,tr[k<<1|1].hma);
}
void add(int L,int R,LL num,int k=1){
  if (tr[k].l==L&&tr[k].r==R){
    tr[k].ma+=num;
    tr[k].tag+=num;
    tr[k].htag=max(tr[k].htag,tr[k].tag);
    tr[k].hma=max(tr[k].hma,tr[k].ma);
    return;
  }
  pushdown(k);
  int mid=tr[k].l+tr[k].r>>1;
  if (R<=mid) add(L,R,num,k<<1);
  else if (L>mid) add(L,R,num,k<<1|1);
    else add(L,mid,num,k<<1),add(mid+1,R,num,k<<1|1);
  pushup(k);
}
LL query(int L,int R,int k=1){
  if (tr[k].l==L&&tr[k].r==R) return tr[k].hma;
  pushdown(k);
  int mid=tr[k].l+tr[k].r>>1;
  if (R<=mid) return query(L,R,k<<1);
  else if (L>mid) return query(L,R,k<<1|1);
    else return max(query(L,mid,k<<1),query(mid+1,R,k<<1|1));
}
inline void work(){
  for (int i=1;i<=n;i++)
    last[i]=lx[a[i]+100000],lx[a[i]+100000]=i;
  sort(q+1,q+1+m,cmp);
  build(1,n);
  int j=1;
  for (int i=1;i<=n;i++){
    add(last[i]+1,i,a[i]);
    for (;j<=m&&q[j].r==i;j++) ans[q[j].id]=query(q[j].l,q[j].r);
  }
}
inline void outo(){
  for (int i=1;i<=m;i++)
    printf("%lld\n",ans[i]);
}
int main(){
  into();
  work();
  outo();
  return 0;
}

T3:
在T1的基础上,增加单点修改的操作.
1 ≤ n , m ≤ 5 ∗ 1 0 4 1\leq n,m\leq 5*10^4 1≤n,m≤5∗104.

这其实跟T1的思路是一样的,多写一个修改函数就可以了.

代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=50000;
struct tree{
  int l,r,sum,ans,lans,rans;
}tr[N*5];
int n,q,a[N+5];
void pushup(int k){
  int ls=k<<1,rs=k<<1|1;
  tr[k].sum=tr[ls].sum+tr[rs].sum;
  tr[k].lans=max(tr[ls].lans,tr[ls].sum+tr[rs].lans);
  tr[k].rans=max(tr[rs].rans,tr[rs].sum+tr[ls].rans);
  tr[k].ans=max(max(tr[ls].ans,tr[rs].ans),tr[ls].rans+tr[rs].lans);
}
void build(int L,int R,int k=1){
  tr[k].l=L;tr[k].r=R;
  if (L==R){
    tr[k].ans=tr[k].lans=tr[k].rans=tr[k].sum=a[L];
    return;
  }
  int mid=L+R>>1;
  build(L,mid,k<<1);build(mid+1,R,k<<1|1);
  pushup(k);
}
void change(int x,int num,int k=1){
  if (tr[k].l==tr[k].r){
    tr[k].sum=tr[k].ans=tr[k].lans=tr[k].rans=num;
    return;
  }
  int mid=tr[k].l+tr[k].r>>1;
  if (x<=mid) change(x,num,k<<1);
  else change(x,num,k<<1|1);
  pushup(k);
}
struct tree1{
  int sum,ans,lans,rans;
};
tree1 query(int L,int R,int k=1){
  if (tr[k].l==L&&tr[k].r==R) return (tree1){tr[k].sum,tr[k].ans,tr[k].lans,tr[k].rans};
  int mid=tr[k].l+tr[k].r>>1;
  if (R<=mid) return query(L,R,k<<1);
  else if (L>mid) return query(L,R,k<<1|1);
    else {
      tree1 u=query(L,mid,k<<1),v=query(mid+1,R,k<<1|1),o;
      o.sum=u.sum+v.sum;
      o.lans=max(u.lans,u.sum+v.lans);
      o.rans=max(v.rans,v.sum+u.rans);
      o.ans=max(max(u.ans,v.ans),u.rans+v.lans);
      return o;
    }
}
Abigail into(){
  scanf("%d",&n);
  for (int i=1;i<=n;i++)
    scanf("%d",&a[i]);
  build(1,n);
  scanf("%d",&q);
}
Abigail work(){
  int opt,x,y;
  for (int i=1;i<=q;i++){
    scanf("%d%d%d",&opt,&x,&y);
    if (opt) printf("%d\n",query(x,y).ans);
    else change(x,y);
  }
}
Abigail outo(){
}
int main(){
  into();
  work();
  outo();
  return 0;
}

T4:
对于一个长度为 n n n的数列,支持下列操作:
1.格式 0 &ThinSpace; l &ThinSpace; r 0\,l\,r 0lr,表示区间开方.
2.格式 1 &ThinSpace; l &ThinSpace; r 1\,l\,r 1lr,表示查询区间和.
设操作次数为 m m m,则 1 ≤ n , m ≤ 1 0 5 1\leq n,m\leq 10^5 1≤n,m≤105.

这道题看起来十分不可做,因为区间开方我们无法支持区间的整体修改.

但是我们可以发现,开方有个很好的性质,就是开方到最后都会变成 0 0 0或者 1 1 1,然后就不会变了.

所以我们可以利用这个性质,每个区间记录是否已经全部为 0 0 0或 1 1 1,若不是,就暴力修改.

那么我们可以证明,因为开方一次数的长度就会变成原来的一半,所以区间开方的操作的使用次数不会很多,不用担心会TLE.

我们可以计算一下总共的复杂度,最多会给每一个点进行 5 5 5次开方就会为 0 0 0或 1 1 1,所以开方次数可以看做常数,一次操作也可以近似地看成 O ( log ⁡ n ) O(\log n) O(logn)的.

事实上如果真的要算的话,一次操作的时间复杂度是均摊 O ( log ⁡ n log ⁡ log ⁡ n ) O(\log n\log\log n) O(lognloglogn)的.

代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000;
struct tree{
  int l,r;
  bool flag;
  LL sum;
}tr[N*5];
int n,q,T;
LL a[N+5];
void pushup(int k){
  tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum;
  if (tr[k<<1].flag&&tr[k<<1|1].flag) tr[k].flag=1;
}
void build(int L,int R,int k=1){
  tr[k].l=L;tr[k].r=R;
  tr[k].flag=0;
  if (L==R) {
    tr[k].sum=a[L];
    if (tr[k].sum==1LL||tr[k].sum==0LL) tr[k].flag=1;
    return;
  }
  int mid=L+R>>1;
  build(L,mid,k<<1);build(mid+1,R,k<<1|1);
  pushup(k);
}
void change(int L,int R,int k=1){
  if (tr[k].flag) return;
  if (tr[k].l==tr[k].r) {
    tr[k].sum=floor(sqrt(tr[k].sum));
    if (tr[k].sum==1LL||tr[k].sum==0LL) tr[k].flag=1;
    return;
  }
  int mid=tr[k].l+tr[k].r>>1;
  if (R<=mid) change(L,R,k<<1);
  else if (L>mid) change(L,R,k<<1|1);
    else change(L,mid,k<<1),change(mid+1,R,k<<1|1);
  pushup(k);
}
LL query(int L,int R,int k=1){
  if (L==tr[k].l&&R==tr[k].r) return tr[k].sum;
  int mid=tr[k].l+tr[k].r>>1;
  if (R<=mid) return query(L,R,k<<1);
  else if (L>mid) return query(L,R,k<<1|1);
    else return query(L,mid,k<<1)+query(mid+1,R,k<<1|1);
}
Abigail into(){
  for (int i=1;i<=n;i++)
    scanf("%lld",&a[i]);
  build(1,n);
  scanf("%d",&q);
}
Abigail work(){
  printf("Case #%d:\n",++T);
  int opt,x,y;
  for (int i=1;i<=q;i++){
    scanf("%d%d%d",&opt,&x,&y);
    if (x>y) swap(x,y);
    if (opt) printf("%lld\n",query(x,y));
    else change(x,y);
  }
  printf("\n");
}
Abigail outo(){
}
int main(){
  while (~scanf("%d",&n)){
    into();
    work();
    outo();
  }
  return 0;
}

T5:
题目大意:给定一串长度为 n n n的数列,维护一个数据结构支持查询左端点在 [ l 1 , r 1 ] [l1,r1] [l1,r1],右端点在 [ l 2 , r 2 ] [l2,r2] [l2,r2]中的最大区间和.
设操作次数为 m m m,则 1 ≤ n , m ≤ 1 0 4 1\leq n,m\leq 10^4 1≤n,m≤104.

这道题准备好分类讨论了.

首先线段树还是那么一棵,但是我们得把这些询问给分几种情况讨论:

当 l 1 = l 2 , r 1 = r 2 l1=l2,r1=r2 l1=l2,r1=r2时,直接计算 [ l 1 , r 1 ] [l1,r1] [l1,r1]的最大子段和.

当 l 1 &lt; = r 1 &lt; l 2 &lt; = r 2 l1&lt;=r1&lt;l2&lt;=r2 l1<=r1<l2<=r2时,那么将这个询问分成三部分,区间 [ l 1 , r 1 ] [l1,r1] [l1,r1]必须包括右端点的最大子段和+区间 [ r 1 + 1 , l 2 − 1 ] [r1+1,l2-1] [r1+1,l2−1]的和+区间 [ l 2 , r 2 ] [l2,r2] [l2,r2]必须包括左端点的最大子段和.

当 l 1 &lt; = l 2 &lt; = r 1 &lt; = r 2 l1&lt;=l2&lt;=r1&lt;=r2 l1<=l2<=r1<=r2时,这种情况询问要分成几种情况:
1.左端点在 [ l 2 , r 1 ] [l2,r1] [l2,r1],右端点也在 [ l 2 , r 1 ] [l2,r1] [l2,r1],那么是区间 [ l 2 , r 1 ] [l2,r1] [l2,r1]的最大子段和.
2.左端点在 [ l 1 , l 2 − 1 ] [l1,l2-1] [l1,l2−1],右端点在 [ l 2 , r 2 ] [l2,r2] [l2,r2],那么是区间 [ l 1 , l 2 − 1 ] [l1,l2-1] [l1,l2−1]的必须包括右端点的最大子段和+区间 [ l 2 , r 2 ] [l2,r2] [l2,r2]必须包括左端点的最大子段和.
3.右端点在 [ r 1 + 1 , r 2 ] [r1+1,r2] [r1+1,r2],左端点在 [ l 1 , r 1 ] [l1,r1] [l1,r1],那么是区间 [ r 1 + 1 , r 2 ] [r1+1,r2] [r1+1,r2]必须包括左端点的最大子段和+区间 [ l 1 , r 1 ] [l1,r1] [l1,r1]必须包括右端点的最大子段和.

那么代码就好写了,不过细节较多:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
#define rep(i,j,k) for (int i=j;i<=k;i++)
typedef long long LL;
const int N=100000;
const int INF=(1<<30)-1+(1<<30);
struct tree{
  int l,r,sum,lsum,rsum,ans;
}tr[N*5];
int n,m,a[N+9];
void build(int L,int R,int k=1){
  tr[k].l=L;tr[k].r=R;
  if(L==R){
    tr[k].sum=tr[k].lsum=tr[k].rsum=tr[k].ans=a[L];
    return;
  }
  int mid=L+R>>1;
  build(L,mid,k<<1);build(mid+1,R,k<<1|1);
  int ls=k<<1,rs=k<<1|1;
  tr[k].ans=tr[ls].ans+tr[rs].ans;
  tr[k].lsum=max(tr[ls].lsum,tr[ls].ans+tr[rs].lsum);
  tr[k].rsum=max(tr[rs].rsum,tr[rs].ans+tr[ls].rsum);
  tr[k].sum=max(max(tr[ls].sum,tr[rs].sum),tr[ls].rsum+tr[rs].lsum);
}
struct tree1{
  int sum,lsum,rsum,ans;
};
tree1 query(int L,int R,int k=1){
  if (R<L) return (tree1){0,0,0,0};
  if (L==tr[k].l&&R==tr[k].r) return (tree1){tr[k].sum,tr[k].lsum,tr[k].rsum,tr[k].ans};
  int mid=tr[k].l+tr[k].r>>1;
  if (R<=mid) return query(L,R,k<<1);
  else if (L>mid) return query(L,R,k<<1|1);
    else {
      tree1 u=query(L,mid,k<<1),v=query(mid+1,R,k<<1|1),o;
      o.ans=u.ans+v.ans;
      o.lsum=max(u.lsum,u.ans+v.lsum);
      o.rsum=max(v.rsum,v.ans+u.rsum);
      o.sum=max(max(u.sum,v.sum),u.rsum+v.lsum);
      return o;
    }
}
Abigail into(){
  memset(tr,0,sizeof(tr));
  scanf("%d",&n);
  for (int i=1;i<=n;i++) scanf("%d",&a[i]);
  scanf("%d",&m);
}
Abigail work(){
  build(1,n);
  int l1,r1,l2,r2;
  for (int i=1;i<=m;i++){
    scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
    if (l1==l2&&r1==r2) printf("%d\n",query(l1,r1).sum);
    else if (r1<l2) printf("%d\n",query(l1,r1).rsum+query(r1+1,l2-1).ans+query(l2,r2).lsum);
      else{
        int o1=query(l2,r1).sum,o2=query(l1,l2-1).rsum+query(l2,r2).lsum,o3=query(r1+1,r2).lsum+query(l1,r1).rsum;
        printf("%d\n",max(max(o1,o2),o3));
      }
  }
}
Abigail outo(){
}
int main(){
  int T=0;
  scanf("%d",&T);
  while (T--){
    into();
    work();
    outo();
  }
  return 0;
}

T6:
题目大意:维护一个数据结构支持在一个长度为 n n n的序列上:
1.格式 I &ThinSpace; x &ThinSpace; y I\,x\,y Ixy,在第 x x x个元素前插入一个元素 y y y.
2.格式 D &ThinSpace; x D\,x Dx,删除第 x x x个元素.
3. 格式 R &ThinSpace; x &ThinSpace; y R\,x\,y Rxy,修改第 x x x个元素的值变为 y y y.
4.格式 Q &ThinSpace; l &ThinSpace; r Q\,l\,r Qlr,查询区间 [ l , r ] [l,r] [l,r]的最大子段和.
设操作次数为 m m m,则 1 ≤ n , m ≤ 1 0 5 1\leq n,m\leq 10^5 1≤n,m≤105.

由于需要支持插入删除的原因,所以我们必须使用平衡树来维护此题.

然而这道题又要维护区间信息,这告诉我们应该使用splay这种数据结构.

其实这道题到这里的时候已经很裸了.

代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
#define rep(i,j,k) for (int i=j;i<=k;i++)
typedef long long LL;
const int N=100000;
const int INF=(1<<30)-1+(1<<30);
struct tree{
  int dad,s[2],size,lans,rans,ans,sum,x;
}tr[N*2+9];
int top,n,q,a[N+9],root;
void pushup(int k){
  int ls=tr[k].s[0],rs=tr[k].s[1];
  tr[k].size=tr[ls].size+tr[rs].size+1;
  tr[k].sum=tr[ls].sum+tr[rs].sum+tr[k].x;
  if (ls&&rs){
    tr[k].lans=max(tr[ls].lans,tr[ls].sum+tr[k].x+max(0,tr[rs].lans));
    tr[k].rans=max(tr[rs].rans,tr[rs].sum+tr[k].x+max(0,tr[ls].rans));
    tr[k].ans=max(max(tr[ls].ans,tr[rs].ans),tr[k].x+max(tr[ls].rans,0)+max(tr[rs].lans,0));
  }else if (!ls&&rs){
    tr[k].lans=tr[k].x+max(tr[rs].lans,0);
    tr[k].rans=max(tr[rs].rans,tr[rs].sum+tr[k].x);
    tr[k].ans=max(tr[rs].ans,tr[k].x+max(tr[rs].lans,0));
  }else if (ls&&!rs){
    tr[k].lans=max(tr[ls].lans,tr[ls].sum+tr[k].x);
    tr[k].rans=tr[k].x+max(tr[ls].rans,0);
    tr[k].ans=max(tr[ls].ans,tr[k].x+max(tr[ls].rans,0));
  }else tr[k].lans=tr[k].rans=tr[k].ans=tr[k].x;
}
void rotate(int k){
  int x=tr[k].dad,y=tr[x].dad,b=tr[x].s[1]==k;
  tr[y].s[tr[y].s[1]==x]=k;tr[k].dad=y;
  tr[x].s[b]=tr[k].s[b^1];tr[tr[k].s[b^1]].dad=x;
  tr[k].s[b^1]=x;tr[x].dad=k;
  pushup(x);pushup(k);
}
void splay(int x,int go){
  int y=tr[x].dad,z=tr[y].dad;
  for (;tr[x].dad^go;rotate(x)){
    y=tr[x].dad,z=tr[y].dad;
    if (z^go) (tr[y].s[0]==x)^(tr[z].s[0]==y)?rotate(x):rotate(y);
  }
  if (!go) root=x;
}
void build(int L,int R){
  int mid=L+R>>1,u=++top;
  tr[top].x=a[mid];
  if (L<=mid-1){
    tr[top+1].dad=u;tr[u].s[0]=top+1;
    build(L,mid-1);
  } 
  if(mid+1<=R){
    tr[top+1].dad=u;tr[u].s[1]=top+1;
    build(mid+1,R);
  }
  pushup(u);
}
int find(int x){
  int u=root;
  while (1)
    if (x<=tr[tr[u].s[0]].size) u=tr[u].s[0];
    else if (x>tr[tr[u].s[0]].size+1) x-=tr[tr[u].s[0]].size+1,u=tr[u].s[1];
      else break;
  splay(u,0);
  return u;
}
void insert(int x,int y){
  int l=find(x-1),r=find(x);
  splay(l,0);splay(r,l);
  tr[r].s[0]=++top;tr[top].dad=r;tr[top].x=y;
  pushup(top);pushup(r);pushup(l);
}
void erase(int x){
  int l=find(x-1),r=find(x+1);
  splay(l,0);splay(r,l);
  tr[r].s[0]=0;
  pushup(r);pushup(l);
}
void change(int x,int y){
  int u=find(x);
  tr[u].x=y;
  pushup(u);
}
int query(int x,int y){
  int l=find(x-1),r=find(y+1);
  splay(l,0);splay(r,l);
  return tr[tr[r].s[0]].ans;
}
char rc(){
  char c=getchar();
  for (;c<'A'||c>'Z';c=getchar());
  return c;
}
int ri(){
  int x=0,y=1;
  char c=getchar();
  for (;c<'0'||c>'9';c=getchar()) if (c=='-') y=-1;
  for (;c<='9'&&c>='0';c=getchar()) x=x*10+c-'0';
  return x*y;
}
Abigail into(){
  n=ri();
  for (int i=1;i<=n;i++)
    a[i]=ri(); 
  q=ri();
}
Abigail work(){
  build(0,n+1);
  root=1;
  int x,y;
  char c;
  for (int i=1;i<=q;i++){
    c=rc();
    switch (c){
      case 'I':x=ri();y=ri();
               insert(x+1,y);
               break;
      case 'D':x=ri();
               erase(x+1);
               break;
      case 'R':x=ri();y=ri();
               change(x+1,y);
               break;
      case 'Q':x=ri();y=ri();
               printf("%d\n",query(x+1,y+1));
               break;
    }
  }
}
Abigail outo(){
}
int main(){
  into();
  work();
  outo();
  return 0;
}

T7:
题目大意:维护一棵节点数为 n n n的树,支持:
1.格式 1 &ThinSpace; a &ThinSpace; b 1\,a\,b 1ab,表示查询点 a a a到点 b b b这条链上的最大子段和.
2.格式 2 &ThinSpace; a &ThinSpace; b &ThinSpace; c 2\,a\,b\,c 2abc,表示将点 a a a到点 b b b这条链上的所有点权修改为 c c c.
设操作次数为 m m m,则 1 ≤ n , m ≤ 1 0 5 1\leq n,m\leq 10^5 1≤n,m≤105.

注意我们可以最大子段和一个元素都不取.

这道题明显就是树链剖分的题,整道题也没有什么难度,大体上就是树链剖分的入门题.

不过注意查询的最大子段和的时候,链与链之间的合并这个东西,我们需要注意,这个东西的顺序是不能改变的,也就是说我们不能交换 u u u和 v v v这样去做了.

这个时候的合并顺序就显得十分的难确定了,但是我们可以先确定 u → l c a ( u , v ) u\rightarrow lca(u,v) u→lca(u,v)这条链一定在 v → l c a ( u , v ) v\rightarrow lca(u,v) v→lca(u,v)这条链左边,得到两条链,然后再合并,这样就会变得较为简单.

我们可以结合下面的图想象一下该怎么结合这个东西:
在这里插入图片描述
代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
#define rep(i,j,k) for (int i=j;i<=k;i++)
typedef long long LL;
const int N=100000;
const int INF=(1<<30)-1+(1<<30);
struct side{
  int y,next;
}e[N*2+9];
struct node{
  int deep,dad,son,size,dfn,top,v;
}nod[N+9];
struct tree{
  int l,r,ans,lans,rans,sum,tag;
  bool flag;      //如果你不加一个flag你会误判一个区间修改权值成0的情况,能活生生把你卡成WA卡一个下午
}tr[N*5];
int n,q,a[N+9],order[N+9],t,top,lin[N+9];
void ins(int X,int Y){
  e[++top].y=Y;
  e[top].next=lin[X];
  lin[X]=top;
}
void dfs1(int k,int fa){
  nod[k].dad=fa;
  nod[k].deep=nod[fa].deep+1;
  nod[k].size=1;
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^fa){
      dfs1(e[i].y,k);
      nod[k].size+=nod[e[i].y].size;
      if (nod[nod[k].son].size<nod[e[i].y].size) nod[k].son=e[i].y;
    }
}
void dfs2(int k,int start){
  nod[k].top=start;
  nod[k].dfn=++t;
  order[t]=k;
  if (nod[k].son) dfs2(nod[k].son,start);
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^nod[k].dad&&e[i].y^nod[k].son) dfs2(e[i].y,e[i].y);
}
void update(int k,int num){
  tr[k].flag=1;
  tr[k].tag=num;
  tr[k].sum=num*(tr[k].r-tr[k].l+1);
  tr[k].lans=tr[k].rans=tr[k].ans=max(0,num*(tr[k].r-tr[k].l+1));
}
void pushup(int k){
  int ls=k<<1,rs=k<<1|1;
  tr[k].sum=tr[ls].sum+tr[rs].sum;
  tr[k].lans=max(tr[ls].lans,tr[ls].sum+tr[rs].lans);
  tr[k].rans=max(tr[rs].rans,tr[rs].sum+tr[ls].rans);
  tr[k].ans=max(max(tr[ls].ans,tr[rs].ans),tr[ls].rans+tr[rs].lans);
}
void pushdown(int k){
  if (!tr[k].flag) return;
  update(k<<1,tr[k].tag);update(k<<1|1,tr[k].tag);
  tr[k].tag=tr[k].flag=0;
}
void build(int L,int R,int k=1){
  tr[k].l=L;tr[k].r=R;
  if (L==R){
    tr[k].lans=tr[k].rans=tr[k].ans=max(tr[k].sum=nod[order[L]].v,0);
    return;
  }
  int mid=L+R>>1;
  build(L,mid,k<<1),build(mid+1,R,k<<1|1);
  pushup(k);
}
void change(int L,int R,int num,int k=1){
  if (L==tr[k].l&&R==tr[k].r){
    update(k,num);
    return;
  }
  pushdown(k);
  int mid=tr[k].l+tr[k].r>>1;
  if (R<=mid) change(L,R,num,k<<1);
  else if (L>mid) change(L,R,num,k<<1|1);
    else change(L,mid,num,k<<1),change(mid+1,R,num,k<<1|1);
  pushup(k);
}
struct tree1{
  int lans,rans,ans,sum;
};
tree1 merge(tree1 u,tree1 v){
  tree1 o;
  o.sum=u.sum+v.sum;
  o.lans=max(u.lans,u.sum+v.lans);
  o.rans=max(v.rans,v.sum+u.rans);
  o.ans=max(max(u.ans,v.ans),u.rans+v.lans);
  return o;
}
tree1 rez(tree1 o){
  swap(o.lans,o.rans);
  return o;
}
tree1 query(int L,int R,int k=1){
  if (L==tr[k].l&&R==tr[k].r) return (tree1){tr[k].lans,tr[k].rans,tr[k].ans,tr[k].sum};
  pushdown(k);
  int mid=tr[k].l+tr[k].r>>1;
  if (R<=mid) return query(L,R,k<<1);
  else if (L>mid) return query(L,R,k<<1|1);
    else return merge(query(L,mid,k<<1),query(mid+1,R,k<<1|1));
}
void Change(int u,int v,int num){
  while (nod[u].top^nod[v].top){
    if (nod[nod[u].top].deep<nod[nod[v].top].deep) swap(u,v);
    change(nod[nod[u].top].dfn,nod[u].dfn,num);
    u=nod[nod[u].top].dad;
  }
  if (nod[u].deep>nod[v].deep) swap(u,v);
  change(nod[u].dfn,nod[v].dfn,num);
}
int Query(int u,int v){      //这个查询好好自己理解一下,对照上面的那个图想象一下
  tree1 fu,fv;
  fu.ans=fu.lans=fu.rans=fu.sum=fv.ans=fv.lans=fv.rans=fv.sum=0;
  while (nod[u].top^nod[v].top)
    if (nod[nod[u].top].deep>nod[nod[v].top].deep){
      fu=merge(fu,rez(query(nod[nod[u].top].dfn,nod[u].dfn)));
      u=nod[nod[u].top].dad;
    }else{
      fv=merge(query(nod[nod[v].top].dfn,nod[v].dfn),fv);
      v=nod[nod[v].top].dad;
    }
  if (nod[u].deep>nod[v].deep) return merge(merge(fu,rez(query(nod[v].dfn,nod[u].dfn))),fv).ans;
  else return merge(fu,merge(query(nod[u].dfn,nod[v].dfn),fv)).ans;
}
Abigail into(){
  scanf("%d",&n);
  for (int i=1;i<=n;i++)
    scanf("%d",&nod[i].v);
  int x,y;
  for (int i=1;i<n;i++){
    scanf("%d%d",&x,&y);
    ins(x,y);ins(y,x);
  }
}
Abigail work(){
  scanf("%d",&q);
  dfs1(1,0);
  dfs2(1,1);
  build(1,n);
  int a,b,c,opt;
  for (int i=1;i<=q;i++){
    scanf("%d",&opt);
    if (opt==1){
      scanf("%d%d",&a,&b);
      printf("%d\n",Query(a,b));
    }else{
      scanf("%d%d%d",&a,&b,&c);
      Change(a,b,c);
    }
  }
}
Abigail outo(){
}
int main(){
  into();
  work();
  outo();
  return 0;
}

T8:
题目大意:维护一个序列 A [ 0.. n − 1 ] A[0..n-1] A[0..n−1],支持:
1.格式 I &ThinSpace; x &ThinSpace; y I\,x\,y Ixy,表示在第 x x x个元素前插入一个元素 y y y.
2.格式 D &ThinSpace; x D\,x Dx,表示删除第 x x x个元素.
3.格式 R &ThinSpace; x &ThinSpace; y R\,x\,y Rxy,表示将第 x x x个元修改为 y y y.
4.格式 Q &ThinSpace; l &ThinSpace; r &ThinSpace; k Q\,l\,r\,k Qlrk,表示查询 ∑ i = l r A [ i ] ∗ ( i − l + 1 ) k &ThinSpace;&ThinSpace; m o d &ThinSpace;&ThinSpace; 2 32 \sum_{i=l}^{r}A[i]*(i-l+1)^{k}\,\,mod\,\,2^{32} ∑i=lr​A[i]∗(i−l+1)kmod232的值.
1 ≤ n , q ≤ 1 0 5 1\leq n,q\leq 10^5 1≤n,q≤105.

这题一看就是一道splay的题,但是难点在于操作4如何处理询问.

其实这道题如果没有 k k k次方的影响会容易很多,但是 k k k次方的话会让很多优美的性质被破坏掉.

这道题我们先考虑 k = 1 k=1 k=1时的情况,我们可以直接考虑两个子区间如何合并成一个区间,我们可以从左右两个子区间的答案和+左区间长度*右区间的和来得到这个区间的答案.

但是当 k k k不是 1 1 1的时候,我们就需要考虑右半边的答案不能直接单纯的拆分成左区间长度的 k k k次方*右区间所有数之和+右区间答案了,这样会产生一些问题.

但是我们的思路还是一样的,要将右半边的答案算出来与左半边相加.

这个时候我们考虑用一个 a n s [ i ] ans[i] ans[i]储存一个区间 k = i k=i k=i时的答案.

那么接下来我们就开始看,我们假设整个区间是 [ l , r ] [l,r] [l,r],区间中点是 m i d mid mid,那么我们该如何得到右半边的答案:
∑ i = m i d + 1 r A [ i ] ( i − l + 1 ) k = ∑ i = m i d + 1 r A [ i ] ( ( m i d − l + 1 ) + ( i − m i d ) ) k \sum_{i=mid+1}^{r}A[i](i-l+1)^k\\ =\sum_{i=mid+1}^{r}A[i]((mid-l+1)+(i-mid))^k i=mid+1∑r​A[i](i−l+1)k=i=mid+1∑r​A[i]((mid−l+1)+(i−mid))k

我们设 x = ( m i d − l + 1 ) x=(mid-l+1) x=(mid−l+1), r s . a n s [ i ] rs.ans[i] rs.ans[i]为区间 [ m i d + 1 , r ] [mid+1,r] [mid+1,r]中 k = i k=i k=i的答案.

那么原始可以变为:
∑ i = m i d + 1 r A [ i ] ( x + i − m i d ) k = ∑ i = m i d + 1 r ( A [ i ] ∑ j = 0 k C k j x k − j ( i − m i d ) j ) ) \sum_{i=mid+1}^{r}A[i](x+i-mid)^k\\ =\sum_{i=mid+1}^{r}(A[i]\sum_{j=0}^{k}C_{k}^{j}x^{k-j}(i-mid)^j)) i=mid+1∑r​A[i](x+i−mid)k=i=mid+1∑r​(A[i]j=0∑k​Ckj​xk−j(i−mid)j))

将 A [ i ] A[i] A[i]也放进去会得到:
∑ i = m i d + 1 r ∑ j = 0 k A [ i ] C k j x k − j ( i − m i d ) j \sum_{i=mid+1}^{r}\sum_{j=0}^{k}A[i]C_{k}^{j}x^{k-j}(i-mid)^j i=mid+1∑r​j=0∑k​A[i]Ckj​xk−j(i−mid)j

我们发现可以用 r s . a n s rs.ans rs.ans代入得到:
∑ j = 0 k C k j x k − j r s . a n s [ j ] \sum_{j=0}^{k}C_{k}^{j}x^{k-j}rs.ans[j] j=0∑k​Ckj​xk−jrs.ans[j]

我们发现这个算式是可以用 O ( k ) O(k) O(k)的时间直接算的,而 k k k又是一个小于 10 10 10的数,所以这样计算右半边并不慢.

那么我们这样就可以把这道题完美AC了.

整个算法的时间复杂度 O ( n k 2 + m k 2 log ⁡ n ) O(nk^2+mk^2\log n) O(nk2+mk2logn),空间复杂度 O ( k ( n + q ) ) O(k(n+q)) O(k(n+q)).

AC代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef unsigned int LL;
const int N=200000;
struct tree{
  LL x,ans[11];
  int fa,s[2],size;
}tr[N+9];
LL C[11][11],a[N+9],po[11];
int n,q,root=1,top;
void start(){
  for (int i=0;i<=10;i++){
    C[i][0]=1;C[i][i]=1;
    for (int j=1;j<i;j++)
      C[i][j]=C[i-1][j-1]+C[i-1][j];
  }
}
void pushup(int k){
  int ls=tr[k].s[0],rs=tr[k].s[1];
  tr[k].size=tr[ls].size+tr[rs].size+1;
  po[0]=1LL;
  for (int i=1;i<=10;i++)
    po[i]=po[i-1]*(tr[ls].size+1);
  for (int i=0;i<=10;i++){
    tr[k].ans[i]=tr[ls].ans[i]+tr[k].x*po[i];
    for (int j=0;j<=i;j++)
      tr[k].ans[i]=tr[k].ans[i]+tr[rs].ans[j]*po[i-j]*C[i][j];
  }
}
void rtt(int x){
  int y=tr[x].fa,z=tr[y].fa,k=tr[y].s[1]==x;
  tr[z].s[tr[z].s[1]==y]=x;tr[x].fa=z;
  tr[y].s[k]=tr[x].s[k^1];tr[tr[x].s[k^1]].fa=y;
  tr[x].s[k^1]=y;tr[y].fa=x;
  pushup(y);pushup(x);
}
void splay(int x,int go){
  while (tr[x].fa^go){
    int y=tr[x].fa,z=tr[y].fa;
    if (z^go)
      (tr[y].s[0]==x)^(tr[z].s[0]==y)?rtt(x):rtt(y);
    rtt(x);
  }
  if (!go) root=x;
}
void build(int L,int R){
  int k=++top,mid=L+R>>1;
  tr[k].x=a[mid];
  if (L<=mid-1) tr[k].s[0]=top+1,tr[top+1].fa=k,build(L,mid-1);
  if (R>=mid+1) tr[k].s[1]=top+1,tr[top+1].fa=k,build(mid+1,R);
  pushup(k);
}
int find(int x){
  int u=root;
  while (1){
    if (x<=tr[tr[u].s[0]].size) u=tr[u].s[0];
    else if (x>tr[tr[u].s[0]].size+1) x-=tr[tr[u].s[0]].size+1,u=tr[u].s[1];
      else break;
  }
  splay(u,0);
  return u;
}
void insert(int x,LL v){
  int l=find(x-1),r=find(x);
  splay(l,0);splay(r,l);
  tr[r].s[0]=++top;tr[top].fa=r;
  tr[top].x=v;
  pushup(top);pushup(r);pushup(l);
}
void erase(int x){
  int l=find(x-1),r=find(x+1);
  splay(l,0);splay(r,l);
  tr[r].s[0]=0;
  pushup(r);pushup(l);
}
void change(int x,LL v){
  int l=find(x);
  splay(l,0);
  tr[l].x=v;
  pushup(l);
}
LL query(int l,int r,int k){
  int L=find(l-1),R=find(r+1);
  splay(L,0);splay(R,L);
  return tr[tr[R].s[0]].ans[k];
}
char rc(){
  char c=getchar();
  for (;c<'A'||c>'Z';c=getchar());
  return c;
}
Abigail into(){
  scanf("%d",&n);
  for (int i=1;i<=n;i++)
    scanf("%u",&a[i]);
  scanf("%d",&q);
}
Abigail work(){
  start();      //调了两天突然发现start没有调用... 
  build(0,n+1);
  int l,r,k;
  LL v;
  char opt;
  for (int i=1;i<=q;i++){
    opt=rc();
    switch (opt){
      case 'I':scanf("%d%u",&l,&v);
               insert(l+2,v);
               break;
      case 'D':scanf("%d",&l);
               erase(l+2);
               break;
      case 'R':scanf("%d%u",&l,&v);
               change(l+2,v);
               break;
      case 'Q':scanf("%d%d%d",&l,&r,&k);
               printf("%u\n",query(l+2,r+2,k));
               break;
    }
  }
}
Abigail outo(){
}
int main(){
  into();
  work();
  outo();
  return 0;
}
[SPOJ]GSS系列(区间查询最大子段和问题) 文章目录1.GSS系列问题2.GSS13.GSS34.GSS45.GSS26.GSS57.写在最后 1.GSS系列问题 是spojspojspoj上的一组数据结构问题 通常是查询最大子段和 找到这组题还是要感谢akioiakioiakioi的gjmgjmgjm GSS=Greatest Sums of SubsegmentsGSS=Greatest\ Sums \ ... 阅读详情

相关推荐

Fofa API高阶玩法:用Python批量获取漏洞资产(含OA系统扫描实战)

本文详细介绍了如何利用Python结合Fofa API实现自动化漏洞资产收集的高阶实战技巧。通过构建健壮的客户端、设计精准查询语法、实现多线程批量采集,并以OA系统漏洞扫描为例,演示了从资产发现、过滤验证到报告生成的全流程,旨在提升安全运维与应急响应的效率。

weixin_28607671的博客 497

数据结构1 题解

题目列表 文章目录**题目列表**A.并查集B.带权并查集C.最短路D.二分E.搜索F.树搜G.差分H.离散化I.离散化+差分J.LCSK.背包问题 A.并查集 B.带权并查集 C.最短路 D.二分 E.搜索 F.树搜 G.差分 H.离散化 I.离散化+差分 J.LCS K.0-1背包 A.并查集 一、题目 [问题描述] 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路

wangdiyi的博客 2543

Python爬虫实战:5分钟搞定东方财富A股数据抓取(附完整代码)

本文提供了一套基于Python的A股数据自动化采集与分析系统构建方案。文章详细解析了如何通过稳健的爬虫框架从东方财富等公开数据源高效抓取A股数据,并设计数据库进行自动化存储与管理,特别适合量化研究和数据分析场景。

weixin_29062963的博客 4429

51nod 3072 线段树练习3

题目描述: 你需要维护一个长为nn的序列,支持mm个操作: 1. 区间中每个数乘xx 2. 区间中每个数加xx 3. 查询区间和 答案对一个常数pp取模 输入 第一行包含三个整数 n,m,p,分别表示该数列数字的个数、操作的总个数和模数。 第二行包含 n 个用空格分隔的整数,其中第 i 个数字表示数列第 i 项的初始值。 接下来 m 行每行包含若干个整数,表示一个操作,具体如下: 操作 1: 格式:`1 x y k` 含义:将区间 [x,y] 内每个数乘上 k 操作 2: 格式:`2.

t56346的博客 202

保姆级教程:用Vue3+Element Plus快速搭建Flowable流程定义管理后台界面

本文提供了一份详细的Vue3+Element Plus教程,指导开发者快速搭建Flowable流程定义管理后台界面。从项目初始化、核心页面设计到响应式数据处理,全面覆盖前端开发关键步骤,帮助提升企业级应用开发效率。

weixin_42662293的博客 479

Qt绘图实战:用QGraphicsItem实现可拖拽箭头连接(附完整代码)

本文详细介绍了如何使用Qt的QGraphicsItem框架实现一个功能完备的可拖拽箭头连接组件。通过核心代码示例,讲解了如何创建自定义图形项、实现智能吸附、碰撞检测以及实时拖拽编辑路径,为构建流程图、拓扑图等专业图形编辑器提供了完整的解决方案。

m2n3b4v5c6的博客 626

最大子段和问题的四种解决办法

文章目录一、题目描述二、解决方法1.穷举法2.优化穷举法3.分治法4.动态规划 一、题目描述 Description 给定有n个整数(可能为负整数)组成的序列a1,a2,…,an,求该序列连续的子段和的最大值。 如果该子段的所有元素和是负整数时定义其最大子段和为0。 Input 第一行有一个正整数n(n<1000),后面跟n个整数,绝对值都小于10000。直到文件结束。 Output 输出它的最大子段和. Sample Input 6 -2 11 -4 13 -5 -2 Sample Output 2

Fariy_immortal的博客 5219

【软件使用】Calibre部分提参的实战技巧与常见问题解析

本文深入解析Calibre部分提参(Partial Extraction)的实战技巧与常见问题,涵盖PEX、hcell和xcell文件的高级应用。通过实际案例展示如何提升电路仿真效率,解决时钟信号失真等复杂问题,并提供版图设计中的防坑指南,助力芯片设计工程师优化工作流程。

weixin_28717431的博客 162

SPOJ - GSS1

线段树。每个节点储存四个值,分别是:该区间内连续的最大值,从左边开始连续的最大值,从右边开始连续的最大值,整段的值。我们知道,区间连续的最大值要么在最左边,要么在最右边,要么在中间的某一部分。每次查询找出“完整覆盖”区间位置,从左往右暴力选择区间的起点和区间的终点。#include &lt;bits/stdc++.h&gt; using namespace std; typedef long ...

vivian_hy的博客 383

S7-1200与ABB机器人进行SOCKET通信的具体方法示例

S7-1200与ABB机器人进行SOCKET通信的具体方法示例

Robot_PLC_HMI_Automation 3293

【MATLAB】工业传送带速度闭环控制与张力联合仿真

本文基于MATLAB/Simulink平台,构建了工业传送带速度闭环控制与张力联合仿真系统。通过搭建驱动模块、机械传动模块、检测模块和控制模块,实现了速度与张力的协同控制。采用双PID调节器分别整定速度与张力参数,经联合调试后系统性能良好:速度跟踪误差小于±0.03m/s,张力波动控制在±30N内,负载扰动恢复时间仅0.3秒。研究提供了从建模到参数优化的完整工程方案,可直接应用于课程设计或工业实践,有效解决了传送带运行中速度偏差与张力波动的协同控制难题。

unber的博客 78

3981 动态最大子段和

题目描述Description 题目还是简单一点好... 有n个数,a[1]到a[n]。 接下来q次查询,每次动态指定两个数l,r,求a[l]到a[r]的最大子段和。 子段的意思是连续非空区间。 输入描述Input Description 第一行一个数n。 第二行n个数a[1]~a[n]。 第三行一个数q。 以下q行每行两个数l和r。 ...

weixin_30298497的博客 154

HyperLynx仿真(一)LineSim简单介绍

可以选择设置信号线与信号线之间默认的距离和信号线与同平面的平面之间的距离,这些设置根据工程师项目上经常使用的情况而设置,也可以选择不设置,在每次仿真时根据需要再对每一个仿真单独设置。仿真属性的设置对话框包含一般设置、 显示颜色设置、LineSim 设置、BoardSim 设置、 层叠默认设置、焊盘类型设置、仿真示波器默认设置、电路仿真器默认设置、电源完整性设置及高级设置。第一次使用HyperLynx软件时需要设置仿真相关环境,包括仿真软件的基本设置、模型库路径设置、仿真控制器控制、单位等。...

小幽余生不加糖 8950

线段树之最大子段和(SPOJ三题)

心得 昨天杭电不会线段树维护最大子段和,补了一下,发现和维护最长01的区间合并是一样的 顺便网上搜了一下子段和的SPOJ的GSS1到GSS8,觉得还挺好的,决定补一下 其中GSS1、GSS2(坑题待补)、GSS3、GSS5是最大子段和,GSS4是区间开根(之前做过就不管了) GSS6、GSS7、GSS8两个是平衡树(treap/splay),一个是树剖,对于目前来说,太难待补 SP...

小衣同学的博客 643

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

【挖坑】【GSS系列】GSS1:区间最大子段和

Can you answer these queries? ​ GSS系列是spoj出品的一套数据结构好毒瘤题,主要以线段树、平衡树和树链剖分为背景,进行了一些操作的魔改,使得难度远超模板题,但对于思维有极大的提升。 ​ 所以我会选择一些在我能力范围内的题挖坑选讲,构成一个GSS系列。至于剩下那些,等我成为巨佬弄懂了再说吧。 GSS1:区间最大子段和 原题传送门(洛谷) 题意 ​ 给定一个序列...

Fighter的博客 608

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

SPOJ GSS1 (区间最大子段和)(线段树)

想要补camp里的那道区间最大k子段和,结果发现自己连怎么求区间最大字段和都不会。。。菜是原罪,于是找了GSS来补一下(虽然我连GSS是什么都不知道hhh 题目 题意 给一个长度为nnn的序列,mmm次查询,每次查询一个区间[l,r][l,r][l,r]中的最大子段和(要求为连续子序列)。 思路 对于一个固定区间,求最大子段和我们有O(n)O(n)O\left(n\right)的...

ShadowGhostH的博客 1270

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

【挖坑】【GSS系列】GSS3:带单点修改的区间最大子段和

Can you answer these queries? ​ GSS系列是spoj出品的一套数据结构好毒瘤题,主要以线段树、平衡树和树链剖分为背景,进行了一些操作的魔改,使得难度远超模板题,但对于思维有极大的提升。 ​ 所以我会选择一些在我能力范围内的题挖坑选讲,构成一个GSS系列。至于剩下那些,等我成为巨佬弄懂了再说吧。 GSS3:带单点修改的区间最大子段和 ​ 本文有前置芝士:GSS1。...

Fighter的博客 565

SPOJ GSS 1~8

GSS是一系列查询区间最大子段和及其变种的题目。GSS 1 ~ 8 的题号分别是:1043 & 1557 & 1716 & 2713 & 2916 & 4487 & 6779 & 19543 目前完成进度:1 (好惨啊,慢慢做吧……)SPOJ 1043 GSS 1应该是不难的。我们假设一个区间的最大子段已经找到,往区间里随便放一条分界线。有两种情况:一是最大子段在分界线的某一边,二是最大子段经过分界

无尽 1476

Can you answer these queries II 【SPOJ - GSS2】【去重最大子段和】

SPOJ-GSS2 题目链接 这道题的思维有点像多个dp同时进行的样子,我们去判断一个子段和是否是最大的,是不是要和之前的做比较如果大于之前的最大子段和就可以去更新掉,这个思维先存在这,后边会用到的。 然后,再讲一下题意,这道题的题意是真的有毒啊……我WA了接近24个小时,20发了,还在猜…… 最后想通了,这道题的题意是这样的: N个a[ i ],我们要去取这样的一个区间,例如“...

既然弱小,就只顾变强就是了 354

spoj GSS1

SPOJ GSS系列题 You are given a sequence A[1], A[2], ..., A[N] . ( |A[i]| ≤ 15007 , 1 ≤ N ≤ 50000 ). A query is defined as follows:  Query(x,y) = Max { a[i]+a[i+1]+...+a[j] ; x ≤ i ≤ j ≤ y }.  Give

zuihoudebingwen的专栏 1842

SPOJ GSS1 ~ 8解题报告 【完整版】

若转载请注明出处!!! GSS1 —— GSS8 简述做法加代码。 GSS1 给出了序列\(A[1]\),\(A[2]\),…,\(A[N]\)。 \((a[i]≤15007,1≤N≤50000)\)。查询定义如下: 查询\((x,y)=max\{a[i]+a[i+1]+...+a[j];x≤i≤j≤y\}\)。 给定M个查询,程序必须输出这些查询的结果。 思路: 我们维护四个值: sum, ls...

weixin_30839881的博客 239

SPOJ GSS3-区间最大连续子段和-Can you answer these queries III

Description You are given a sequence A of N (N <= 50000) integers between -10000 and 10000. On this sequence you have to apply M (M <= 50000) operations: modify the i-th element in the sequence ...

Nothing_but_Fight的博客 298

线段树维护(最大区间和,最大子段和,最长连续上升子序列)

本文主要介绍用线段树来维护(最大区间和,最大子段和,最长连续上升子序列)的问题。 HDU 1540 Tunnel Warfare(最长连续区间+单点修改) 洛谷 P2894 [USACO08FEB]酒店Hotel(最长连续区间+区间修改) 吉首大学2019年程序设计竞赛-白山茶与红玫瑰(最长连续区间+区间修改) SPOJ - GSS1 Can you answer these querie...

不二君 2794

SPOJ GSS系列

众所周知的仅次于ynoi的毒瘤数据结构系列。(跟Qtree系列并列?) GSS1: 长度为 $n$ 的序列 $a$,$m$ 个询问,每次询问区间 $[l,r]$ 之间的最大子段和。 $1\le n,m\le 5\times 10^4$。 经典的线段树题。 每个节点维护四个值:$sum,lmax,rmax,amax$。 $sum$ 表示整个区间的和。 $lmax$ 表示以...

angzuo8655的博客 314

spoj GSS系列简要题解

文章目录GSS1GSS2GSS3GSS4GSS5GSS6GSS7GSS8 [传送门] (https://vjudge.net/problem#OJId=SPOJ&amp;amp;amp;amp;probNum=GSS&amp;amp;amp;amp;title=&amp;amp;amp;amp;source=&amp;amp;amp;amp;category=all) 这个GSSGSSGSS系列全部是跟子段有关的数据结构菜题。 于是来水一篇博客。 GSS1 传送门 题意简述:

苟为蒟蒻又何妨 386
上一篇: BZOJ2154 Crash的数字表格及其拓展BZOJ2693 jzptab(Mobius反演)
下一篇: 【HNOI2009】BZOJ1485 有趣的数列题解(Catalan数)
hezlik
博客等级 码龄9年 111粉丝 241原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值