1.GSS系列问题
是
上的一组数据结构问题
通常是查询最大子段和
找到这组题还是要感谢
的
这里是按我洛谷认为的难度顺序排序的
2.GSS1
GSS系列第一题传送门
纯粹的维护最大子段和
怎么做呢?
我们考虑,在合并两颗子树的时候,最大子段和会在哪一部分
1.在左子树内=>
2.在右子树内=>
3.在中间=>
其中
表示最大前缀和,
表示最大后缀和
那么我们考虑最大前缀和和最大后缀和怎么确定
以最大前缀和为例
1.左子树的最大前缀和=>
2.左子树+右子树的最大前缀和=>
其中
表示区间和
然后就没了
# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=1e5+5;
const int inf=0x7fffffff;
const double eps=1e-7;
template <typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
int n,m;
int a[N];
struct segment_tree{
int sumf,sumb;
int sum;
int ans;
int l,r;
}seg[N<<2];
# define lc (u<<1)
# define rc (u<<1|1)
void pushup(int u){
seg[u].sumf=max(seg[lc].sumf,seg[lc].sum+seg[rc].sumf);
seg[u].sumb=max(seg[rc].sumb,seg[rc].sum+seg[lc].sumb);
seg[u].sum=seg[lc].sum+seg[rc].sum;
seg[u].ans=max(max(seg[lc].ans,seg[rc].ans),seg[lc].sumb+seg[rc].sumf);
}
void build(int u,int l,int r){
seg[u].l=l,seg[u].r=r;
if(l==r){seg[u].sumf=seg[u].sumb=seg[u].sum=seg[u].ans=a[l];return;}
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
pushup(u);
}
segment_tree query(int u,int l,int r){
if(seg[u].l>=l&&seg[u].r<=r)return seg[u];
int mid=seg[u].l+seg[u].r>>1;
if(r<=mid)return query(lc,l,r);
if(l>mid)return query(rc,l,r);
segment_tree ls=query(lc,l,r),rs=query(rc,l,r),res;
res.sumf=max(ls.sumf,ls.sum+rs.sumf);
res.sumb=max(rs.sumb,rs.sum+ls.sumb);
res.sum=ls.sum+rs.sum;
res.ans=max(max(ls.ans,rs.ans),ls.sumb+rs.sumf);
return res;
}
int main()
{
read(n);
Rep(i,1,n)read(a[i]);
build(1,1,n);
read(m);
Rep(i,1,m){
int l,r;
read(l),read(r);
printf("%d\n",query(1,l,r).ans);
}
return 0;
}
3.GSS3
传送门
这道题跟上一个没啥区别…
加一个
就好了
对了,这题可以算三倍经验
算上GSS1,还有一道小白逛公园
# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=1e5+5;
const int inf=0x7fffffff;
const double eps=1e-7;
template <typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
int n,m;
int a[N];
struct segment_tree{
int sumf,sumb;
int sum;
int ans;
int l,r;
}seg[N<<2];
# define lc (u<<1)
# define rc (u<<1|1)
void pushup(int u){
seg[u].sumf=max(seg[lc].sumf,seg[lc].sum+seg[rc].sumf);
seg[u].sumb=max(seg[rc].sumb,seg[rc].sum+seg[lc].sumb);
seg[u].sum=seg[lc].sum+seg[rc].sum;
seg[u].ans=max(max(seg[lc].ans,seg[rc].ans),seg[lc].sumb+seg[rc].sumf);
}
void build(int u,int l,int r){
seg[u].l=l,seg[u].r=r;
if(l==r){seg[u].sumf=seg[u].sumb=seg[u].sum=seg[u].ans=a[l];return;}
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
pushup(u);
}
void update(int u,int x,int k){
if(seg[u].l==seg[u].r){seg[u].sumf=seg[u].sumb=seg[u].sum=seg[u].ans=k;return;}
int mid=seg[u].l+seg[u].r>>1;
if(x<=mid)update(lc,x,k);
else update(rc,x,k);
pushup(u);
}
segment_tree query(int u,int l,int r){
if(seg[u].l>=l&&seg[u].r<=r)return seg[u];
int mid=seg[u].l+seg[u].r>>1;
if(r<=mid)return query(lc,l,r);
if(l>mid)return query(rc,l,r);
segment_tree ls=query(lc,l,r),rs=query(rc,l,r),res;
res.sumf=max(ls.sumf,ls.sum+rs.sumf);
res.sumb=max(rs.sumb,rs.sum+ls.sumb);
res.sum=ls.sum+rs.sum;
res.ans=max(max(ls.ans,rs.ans),ls.sumb+rs.sumf);
return res;
}
int main()
{
read(n);
Rep(i,1,n)read(a[i]);
build(1,1,n);
read(m);
Rep(i,1,m){
int opt,x,y;
read(opt),read(x),read(y);
if(!opt)update(1,x,y);
if(opt)printf("%d\n",query(1,x,y).ans);
}
return 0;
}
4.GSS4
传送门
这道题好像跟最大子段和没什么关系。。。
我们观察发现
是
次方级别,但是他开最多六次根就变成1了,这样继续下去是不会变的,所以当一个区间全是1的时候,就不用管他了,下次再询问的时候直接返回区间长度‘’
如果不是1就暴力修改就好了
这里用的是树状数组和并查集
对了,这题也是双倍经验
上帝造题的七分钟2 花神游历各国
# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <stack>
# include <ctime>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define mct(a,b) memset(a,b,sizeof(a))
# define gc getchar()
typedef long long ll;
const int N=1e6+5;
const int inf=0x7fffffff;
const int mod=1e9+7;
template <typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
# define int ll
int n,m;
ll a[N];
ll bit[N];
int fa[N];
inline int lowbit(int o){
return o&(-o);
}
inline void add(int o,int x){
for(;o<=n;o+=lowbit(o))bit[o]+=x;
}
inline ll ask(int o){
ll res=0;
for(;o;o-=lowbit(o))res+=bit[o];
return res;
}
int find(int x){
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
inline void update(int l,int r){
for(int i=l;i<=r;i++,i=find(i)){
ll s=1ll*sqrt(a[i]);
add(i,(s-a[i]));
a[i]=s;
if(a[i]<=1)fa[i]=i+1;
}
}
signed main()
{
read(n);
Rep(i,1,n)read(a[i]),add(i,a[i]);
Rep(i,1,N-1)fa[i]=i;
read(m);
Rep(i,1,m){
ll opt,x,y;
read(opt),read(x),read(y);
if(x>y)swap(x,y);
if(!opt)update(x,y);
else printf("%lld\n",ask(y)-ask(x-1));
}
return 0;
}
5.GSS2
传送门
人生第三道黑题呀QAQ
虽然这道题只比GSS1多几个字,难度真的是难了不只一点
对于这种奇奇怪怪的题目,我们可以考虑离线做(因为他并没有强制在线)
我们先将询问离线,然后按照右端点排序,为什么要这么做呢?我们就可以从1到
扫一遍然后再做
我们先不考虑去重的问题
当我们扫到
的时候
我们让线段树的第
个叶子节点维护
的和
对于询问
的时候的答案是第
~
的所有叶子节点的最大值
我们再来考虑去重,我们在从左往右扫的时候,我们只要把 这一区间里的点加上 就可以了,其中 表示 上一次在哪里出现过
然后就没有什么了吧…
线段树维护两个量,一个是这个子树的和,一个是这个子树包含的所有叶子节点的最大值
因为我们需要区间修改,所以再来两个懒标记
然后因为 可能有负数,所以要把 数组平移一下就好了QAQ
这题不知道有没有双倍经验,反正我目前没找到
# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=1e5+5;
const int mod=1e9+7;
const int move=1e5;
template <typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
int n,m;
int a[N],last[N<<1],pre[N];
int out[N];
struct segment_tree{
int l,r;
int sum,ans;
int tagsum,tagans;
}seg[N<<2];
struct Query{
int l,r,id;
bool operator < (const Query &cmp)const{
return r<cmp.r;
}
}q[N];
# define lc (u<<1)
# define rc (u<<1|1)
void pushup(int u){
seg[u].sum=max(seg[lc].sum,seg[rc].sum);
seg[u].ans=max(seg[lc].ans,seg[rc].ans);
}
void pushdown(int u){
seg[lc].ans=max(seg[lc].ans,seg[lc].sum+seg[u].tagans);
seg[lc].sum+=seg[u].tagsum;
seg[lc].tagans=max(seg[lc].tagans,seg[lc].tagsum+seg[u].tagans);
seg[lc].tagsum+=seg[u].tagsum;
seg[rc].ans=max(seg[rc].ans,seg[rc].sum+seg[u].tagans);
seg[rc].sum+=seg[u].tagsum;
seg[rc].tagans=max(seg[rc].tagans,seg[rc].tagsum+seg[u].tagans);
seg[rc].tagsum+=seg[u].tagsum;
seg[u].tagsum=seg[u].tagans=0;
}
void build(int u,int l,int r){
seg[u].l=l,seg[u].r=r;
if(l==r)return;
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
}
void update(int u,int l,int r,int k){
if(seg[u].l>=l&&seg[u].r<=r){
seg[u].sum+=k;
seg[u].ans=max(seg[u].sum,seg[u].ans);
seg[u].tagsum+=k;
seg[u].tagans=max(seg[u].tagans,seg[u].tagsum);
return;
}
pushdown(u);
int mid=seg[u].l+seg[u].r>>1;
if(l<=mid)update(lc,l,r,k);
if(r>mid)update(rc,l,r,k);
pushup(u);
}
int query(int u,int l,int r){
if(seg[u].l>=l&&seg[u].r<=r)return seg[u].ans;
pushdown(u);
int mid=seg[u].l+seg[u].r>>1;
int res=0;
if(l<=mid)res=max(res,query(lc,l,r));
if(r>mid)res=max(res,query(rc,l,r));
return res;
}
int main()
{
read(n);
Rep(i,1,n){
read(a[i]);
pre[i]=last[a[i]+move];//平移
last[a[i]+move]=i;
}
read(m);
Rep(i,1,m){
read(q[i].l),read(q[i].r);//离线
q[i].id=i;
}
sort(q+1,q+m+1);
build(1,1,n);
int j=1;
Rep(i,1,n){
update(1,pre[i]+1,i,a[i]);//更新
for(;j<=m&&q[j].r<=i;j++)
out[q[j].id]=query(1,q[j].l,q[j].r);//查询
}
Rep(i,1,m)printf("%d\n",out[i]);
return 0;
}
6.GSS5
人生第四道黑题呀QAQ
这道题我们很明显会有一个想法是线段是维护前缀和,每次从
中找最小,在
中找最大,然后一减
黑题?我切了——
黑题可能让你那么简单就水过了吗…还有一句话呢
这个东西怎么做呢?
我们考虑,当
时,答案可能在哪里
1.左端点位于
,右端点位于
=>上面最开始的做法
2.左端点位于
,右端点位于
=>上面最开始的做法
3.左右端点都位于
时间=>GSS3粘过来
所以这道题我们需要维护
1.前缀和的区间
2.前缀和的区间
3.
的最大子段和(以及剩下的三个东西)
然后就没了
对了,这道题我写前缀和一直 ,后来写了后缀和就A了???( 蜜汁
# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=1e5+5;
const int mod=1e9+7;
const double eps=1e-7;
template <typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
int t,n,m;
int a[N];
int sum[N];
struct segment_tree{
int l,r;
int _min,_max;
int sum,ans,lmax,rmax;
}seg[N<<2];
# define lc (u<<1)
# define rc (u<<1|1)
void pushup(int u){
seg[u]._min=min(seg[lc]._min,seg[rc]._min);
seg[u]._max=max(seg[lc]._max,seg[rc]._max);
seg[u].sum=seg[lc].sum+seg[rc].sum;
seg[u].lmax=max(seg[lc].lmax,seg[lc].sum+seg[rc].lmax);
seg[u].rmax=max(seg[rc].rmax,seg[rc].sum+seg[lc].rmax);
seg[u].ans=max(seg[lc].rmax+seg[rc].lmax,max(seg[lc].ans,seg[rc].ans));
}
void build(int u,int l,int r){
seg[u].l=l,seg[u].r=r;
if(l==r){
seg[u]._min=sum[l];
seg[u]._max=sum[l]+a[l]; //这里记得加上去,因为我们查询的时候多减去了一个a[l]
seg[u].sum=seg[u].ans=seg[u].lmax=seg[u].rmax=a[l];
return;
}
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
pushup(u);
}
int Getmax(int u,int l,int r){
if(seg[u].l>=l&&seg[u].r<=r)return seg[u]._max;
int mid=seg[u].l+seg[u].r>>1;
int res=-1e9;
if(l<=mid)res=max(res,Getmax(lc,l,r));
if(r>mid)res=max(res,Getmax(rc,l,r));
return res;
}
int Getmin(int u,int l,int r){
if(seg[u].l>=l&&seg[u].r<=r)return seg[u]._min;
int mid=seg[u].l+seg[u].r>>1;
int res=1e9;
if(l<=mid)res=min(res,Getmin(lc,l,r));
if(r>mid)res=min(res,Getmin(rc,l,r));
return res;
}
segment_tree Getans(int u,int l,int r){
if(seg[u].l>=l&&seg[u].r<=r)return seg[u];
int mid=seg[u].l+seg[u].r>>1;
if(r<=mid)return Getans(lc,l,r);
if(l>mid)return Getans(rc,l,r);
segment_tree a,b,c;
a=Getans(lc,l,r),b=Getans(rc,l,r);
c.sum=a.sum+b.sum;
c.lmax=max(a.lmax,a.sum+b.lmax);
c.rmax=max(b.rmax,b.sum+a.rmax);
c.ans=max(a.rmax+b.lmax,max(a.ans,b.ans));
return c;
}
int main()
{
read(t);
while(t--){
read(n);
Rep(i,1,n)read(a[i]);
sum[0]=0;
_Rep(i,n-1,1)sum[i]=sum[i+1]+a[i+1];//后缀和
build(1,1,n);
read(m);
Rep(i,1,m){
int x1,y1,x2,y2;
read(x1),read(y1),read(x2),read(y2);
int ans=-1e9;
if(y1<=x2)ans=max(ans,-Getmin(1,x2,y2)+Getmax(1,x1,y1));
else{
ans=max(ans,Getans(1,x2,y1).ans);
ans=max(ans,-Getmin(1,y1,y2)+Getmax(1,x1,y1));
ans=max(ans,-Getmin(1,x2,y2)+Getmax(1,x1,x2));
}
printf("%d\n",ans);
}
}
return 0;
}
7.GSS6
题目传送门
这道题看到有插入删除操作,自然想到平衡树
然后就是继续按照GSS1和GSS3的做法,维护那几个量
就可以了
因为我比较菜,只会
,所以这题就打了个170多行的
加上若干行优化到了220行量级
如果
了就好好查查
有没有写对吧
像我update错3处
如果
了就把数组开大点,因为还有插入操作,开
是不够的
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=2e5+5;
const int mod=1e9+7;
const double eps=1e-7;
template <typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
# define debug puts("QAQ")
int n,m;
int a[N];
int fa[N],son[N][2],siz[N],sum[N],key[N],lmax[N],rmax[N],ans[N];
int tot,rt;
int create(int x,int faz){
tot++;
fa[tot]=faz;
son[tot][0]=son[tot][1]=0;
sum[tot]=key[tot]=ans[tot]=x;
lmax[tot]=rmax[tot]=max(x,0);
siz[tot]=1;
return tot;
}
bool locate(int x){return son[fa[x]][1]==x;}
void clear(int x){fa[x]=son[x][0]=son[x][1]=siz[x]=sum[x]=key[x]=lmax[x]=rmax[x]=ans[x]=0;}
void update(int u){
siz[u]=1,sum[u]=key[u];
if(son[u][0])siz[u]+=siz[son[u][0]],sum[u]+=sum[son[u][0]];
if(son[u][1])siz[u]+=siz[son[u][1]],sum[u]+=sum[son[u][1]];
if(!son[u][0]&&!son[u][1]){
ans[u]=key[u];
lmax[u]=rmax[u]=max(key[u],0);
return;
}
if(!son[u][0]){
lmax[u]=max(key[u]+lmax[son[u][1]],0);
rmax[u]=max(max(rmax[son[u][1]],sum[son[u][1]]+key[u]),0);
ans[u]=max(ans[son[u][1]],lmax[son[u][1]]+key[u]);
return;
}
if(!son[u][1]){
lmax[u]=max(max(lmax[son[u][0]],sum[son[u][0]]+key[u]),0);
rmax[u]=max(key[u]+rmax[son[u][0]],0);
ans[u]=max(ans[son[u][0]],rmax[son[u][0]]+key[u]);
return;
}
else{
lmax[u]=max(lmax[son[u][0]],sum[son[u][0]]+key[u]+lmax[son[u][1]]);
rmax[u]=max(rmax[son[u][1]],sum[son[u][1]]+key[u]+rmax[son[u][0]]);
ans[u]=max(rmax[son[u][0]]+key[u]+lmax[son[u][1]],max(ans[son[u][0]],ans[son[u][1]]));
return;
}
}
void rotate(int x){
int faz=fa[x],grand=fa[faz],side=locate(x);
son[faz][side]=son[x][side^1],fa[son[faz][side]]=faz;
son[x][side^1]=faz,fa[faz]=x;
fa[x]=grand;
if(grand)son[grand][son[grand][1]==faz]=x;
update(faz),update(x);
}
void splay(int x,int tar){
if(!tar)rt=x;
while(fa[x]!=tar){
if(fa[fa[x]]!=tar)rotate(locate(x)==locate(fa[x])?fa[x]:x);
rotate(x);
}
}
void build(int u,int l,int r){
int mid=l+r>>1;
key[u]=a[mid];
if(l<mid){
son[u][0]=create(0,u);
build(son[u][0],l,mid-1);
}
if(r>mid){
son[u][1]=create(0,u);
build(son[u][1],mid+1,r);
}
update(u);
}
int kth(int k){
int u=rt;
while(1){
if(son[u][0]&&k<=siz[son[u][0]])u=son[u][0];
else{
int sum=siz[son[u][0]]+1;
if(k<=sum)return u;
u=son[u][1],k-=sum;
}
}
}
void insert(int x,int k){
splay(kth(x),0);
splay(kth(x+1),rt);
x=son[rt][1];
son[x][0]=create(k,x);
update(son[x][0]);
update(x),update(rt);
}
void erase(int x){
splay(kth(x),0);
splay(kth(x+1),rt);
x=son[rt][1];
fa[son[x][1]]=rt;
son[rt][1]=son[x][1];
clear(x);
update(rt);
}
void reset(int x,int k){
splay(kth(x+1),0);
key[rt]=k;
update(rt);
}
int query(int l,int r){
splay(kth(l),0);
splay(kth(r+2),rt);
return ans[son[son[rt][1]][0]];
}
int main()
{
read(n);
Rep(i,1,n)read(a[i]);
rt=create(0,0);
build(rt,0,n+1);
read(m);
Rep(i,1,m){
char opt[10];
int x,y;
scanf("%s%d",opt,&x);
switch(opt[0]){
case 'I':read(y),insert(x,y);break;
case 'D':erase(x);break;
case 'R':read(y),reset(x,y);break;
case 'Q':read(y),printf("%d\n",query(x,y));break;
}
}
return 0;
}
8.GSS7
题目传送门
这个就是一个树链剖分套上
但是注意我们在
两段的答案的时候,
函数是不满足交换律的(想当然在这里
了好久)
然后最后要把
往上跳的那一段的左右最大值交换(因为要整段取反)
# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=1e5+5;
const int mod=1e9+7;
const double eps=1e-7;
template <typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
int n,q;
int a[N],_a[N];
int head[N],cnt;
int faz[N],son[N],dep[N],siz[N],dfn[N],top[N],tot;
struct Edge{
int to,next;
}e[N<<1];
void add(int x,int y){
e[++cnt]=(Edge){y,head[x]},head[x]=cnt;
}
struct node{
int l,r;
int cov,tag;
int sum,lmax,rmax,ans;
node(){cov=tag=sum=lmax=rmax=ans=l=r=0;}
}seg[N<<2];
# define lc (u<<1)
# define rc (u<<1|1)
void cover(int u,int k){
seg[u].sum=k*(seg[u].r-seg[u].l+1);
seg[u].lmax=seg[u].rmax=seg[u].ans=max(seg[u].sum,0);
seg[u].cov=1;
seg[u].tag=k;
}
void pushup(int u){
seg[u].sum=seg[lc].sum+seg[rc].sum;
seg[u].lmax=max(seg[lc].lmax,seg[lc].sum+seg[rc].lmax);
seg[u].rmax=max(seg[rc].rmax,seg[rc].sum+seg[lc].rmax);
seg[u].ans=max(seg[lc].rmax+seg[rc].lmax,max(seg[lc].ans,seg[rc].ans));
}
node merge(node l,node r){
node res;
res.sum=l.sum+r.sum;
res.lmax=max(l.lmax,l.sum+r.lmax);
res.rmax=max(r.rmax,r.sum+l.rmax);
res.ans=max(l.rmax+r.lmax,max(l.ans,r.ans));
res.cov=res.tag=0;
return res;
}
void pushdown(int u){
cover(lc,seg[u].tag);
cover(rc,seg[u].tag);
seg[u].cov=seg[u].tag=0;
}
void build(int u,int l,int r){
seg[u].l=l,seg[u].r=r;
if(l==r){
seg[u].sum=_a[l];
seg[u].lmax=seg[u].rmax=seg[u].ans=max(_a[l],0);
return;
}
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
pushup(u);
}
void update(int u,int l,int r,int k){
if(seg[u].l>=l&&seg[u].r<=r){
cover(u,k);
return;
}
if(seg[u].cov)pushdown(u);
int mid=seg[u].l+seg[u].r>>1;
if(l<=mid)update(lc,l,r,k);
if(r>mid)update(rc,l,r,k);
pushup(u);
}
node query(int u,int l,int r){
if(seg[u].l>=l&&seg[u].r<=r)return seg[u];
if(seg[u].cov)pushdown(u);
int mid=seg[u].l+seg[u].r>>1;
if(r<=mid)return query(lc,l,r);
if(l>mid)return query(rc,l,r);
node lson=query(lc,l,r),rson=query(rc,l,r);
return merge(lson,rson);
}
int RouteQuery(int x,int y){
node l,r;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]){
r=merge(query(1,dfn[top[y]],dfn[y]),r);
y=faz[top[y]];
}
else{
l=merge(query(1,dfn[top[x]],dfn[x]),l);
x=faz[top[x]];
}
}
if(dep[x]>dep[y])l=merge(query(1,dfn[y],dfn[x]),l);
else r=merge(query(1,dfn[x],dfn[y]),r);
swap(l.lmax,l.rmax);
return merge(l,r).ans;
}
void RouteCover(int x,int y,int k){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
update(1,dfn[top[x]],dfn[x],k);
x=faz[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
update(1,dfn[x],dfn[y],k);
}
void dfs1(int u,int fa){
faz[u]=fa;
dep[u]=dep[fa]+1;
siz[u]=1;
RepG(i,u){
int v=e[i].to;
if(v==fa)continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs2(int u,int _top){
top[u]=_top;
dfn[u]=++tot;
_a[tot]=a[u];
if(!son[u])return;
dfs2(son[u],_top);
RepG(i,u){
int v=e[i].to;
if(v==faz[u]||v==son[u])continue;
dfs2(v,v);
}
}
int main()
{
memset(head,-1,sizeof(head));
read(n);
Rep(i,1,n)read(a[i]);
Rep(i,1,n-1){
int x,y;
read(x),read(y);
add(x,y),add(y,x);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
read(q);
while(q--){
int opt,x,y,z;
read(opt),read(x),read(y);
if(opt==1)printf("%d\n",RouteQuery(x,y));
else read(z),RouteCover(x,y,z);
}
return 0;
}
9.GSS8
题目传送门
占坑,待填
可能永远不会填了据说要用二项式定理之类的毒瘤东西
10.写在最后
这篇
并没有更新完
还是要感谢
找到了这么好的一组题