以下内容参考了这里
SPOJ的GSS系列是一些与序列和有关的题目,可以拿来做线段树练手题…
为方便提交,我加上了题目连接…话说有人知道怎么在SPOJ搜题吗?窝只能
Google
…
GSS1:
题目大意:
给定一个序列,求某区间内最大的连续和
题解:
用一棵线段树维护即可,维护
lmax
(该区间内包括左端点的最大的连续和),
rmax
(该区间内包括右端点的最大连续和),
mmax
(该区间内的最大连续和),
sum
(该区间元素的和)四个域
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=int(5*1e4+5);
int s,t;
int read(){
int r=0;char c;bool sign=0;
while(c=getchar(),c=='-'?sign=1:0,!isdigit(c));
while(r=r*10+c-'0',isdigit(c=getchar()));
return sign?-r:r;
}
struct Sta{
int lmax,rmax,mmax,sum;
Sta(int x=0){lmax=rmax=mmax=sum=x;}
Sta operator + (const Sta& b) const {
Sta ans;
ans.sum=sum+b.sum;
ans.lmax=max(lmax,sum+b.lmax);
ans.rmax=max(b.rmax,b.sum+rmax);
ans.mmax=max(max(mmax,b.mmax),rmax+b.lmax);
return ans;
}
};struct SGT{
SGT *ls,*rs;
int l,r,mid;
Sta sta;
SGT(){}
SGT(int l,int r):ls(NULL),rs(NULL),l(l),r(r){mid=l+r>>1;}
void Build();
void Push_Up(){sta=ls->sta+rs->sta;}
Sta Query(){
if(s<=l && t>=r) return sta;
if(s<=mid && t>mid) return ls->Query()+rs->Query();
return s<=mid?ls->Query():rs->Query();
}
}*root,mp[MAXN<<2]; int cnt=0;
SGT* New(int l,int r){
mp[cnt]=SGT(l,r);
return &mp[cnt++];
}void SGT::Build(){
if(l==r) {sta=Sta(read());return;}
(ls=New(l ,mid))->Build();
(rs=New(mid+1,r ))->Build();
Push_Up();
}
int main(){
int n=read();
(root=New(1,n))->Build();
int m=read();
while(m--){
s=read();t=read();
printf("%d\n",root->Query().mmax);
}
return 0;
}
GSS2:
题目大意:
在GSS1的基础上,要求在每个连续和中,重复数字只算一次
题解:
离线大法好,将查询按右端点排序,从左到右依次处理,当前位置为
i
,线段树每个节点代表区间
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=int(1e5+5),INF=0xc0c0c0c0;
int s,t,c;
int ans[MAXN],a[MAXN],Pos[MAXN<<1];
int read(){
int r=0;char c;bool sign=0;
while(c=getchar(),c=='-'?sign=1:0,!isdigit(c));
while(r=r*10+c-'0',isdigit(c=getchar()));
return sign?-r:r;
}struct Q{
int l,r,id;
bool operator < (const Q &b) const {return r<b.r;}
void Read(int i) {l=read();r=read();id=i;}
}q[MAXN];
struct SGT{
SGT *ls,*rs;
int l,r,mid;
int add,_add,mmax,_mmax;
SGT(){}
SGT(int l,int r):ls(0x0),rs(0x0),l(l),r(r){mid=l+r>>1;add=_add=mmax=_mmax=0;}
void Build();
void Push_Up() {mmax=max(ls->mmax,rs->mmax); _mmax=max(ls->_mmax,rs->_mmax);}
void _Add(int c) {_add=max(_add,add+c);_mmax=max(_mmax,mmax+c);}
void Add(int c) {add+=c;mmax+=c;}
void Push_Down(){
if(_add) ls->_Add(_add),rs->_Add(_add),_add=0;
if( add) ls-> Add( add),rs-> Add( add), add=0;
}void Up_Data(){
if(s<=l&&t>=r) {_Add(c);Add(c);return;}
Push_Down();
if(s<=mid) ls->Up_Data();
if(t> mid) rs->Up_Data();
Push_Up();
}int Query(){
if(s<=l&&t>=r) return _mmax;
Push_Down();
int ans=INF;
if(s<=mid) ans=max(ans,ls->Query());
if(t> mid) ans=max(ans,rs->Query());
return ans;
}
}*root,mp[MAXN<<2];int cnt=0;
SGT* New(int l,int r){
mp[cnt]=SGT(l,r);
return &mp[cnt++];
}void SGT::Build(){
if(l==r) return;
(ls=New( l,mid))->Build();
(rs=New(mid+1, r))->Build();
}
int main(){
int *pos=Pos+MAXN;
int n=read();
(root=New(1,n))->Build();
for(int i=1;i<=n;i++) a[i]=read();
int m=read();
for(int i=0;i<m;i++) q[i].Read(i);
sort(q,q+m);
for(int i=1,j=0;i<=n && j<m;i++){
s=pos[a[i]]+1,t=i=pos[c=a[i]]=i;
root->Up_Data();
for(;j<m && i==q[j].r;j++){
s=q[j].l,t=q[j].r;
ans[q[j].id]=root->Query();
}
}
for(int i=0;i<m;i++) printf("%d\n",ans[i]);
return 0;
}
GSS3:
题目大意:
在GSS1的基础上加上单点修改
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=int(5*1e4+5);
int s,t,v,c;
int read(){
int r=0;char c;bool sign=0;
while(c=getchar(),c=='-'?sign=1:0,!isdigit(c));
while(r=r*10+c-'0',isdigit(c=getchar()));
return sign?-r:r;
}
struct Sta{
int lmax,rmax,mmax,sum;
Sta(int x=0){lmax=rmax=mmax=sum=x;}
Sta operator + (const Sta& b) const {
Sta ans;
ans.sum=sum+b.sum;
ans.lmax=max(lmax,sum+b.lmax);
ans.rmax=max(b.rmax,b.sum+rmax);
ans.mmax=max(max(mmax,b.mmax),rmax+b.lmax);
return ans;
}
};struct SGT{
SGT *ls,*rs;
int l,r,mid;
Sta sta;
SGT(){}
SGT(int l,int r):ls(NULL),rs(NULL),l(l),r(r){mid=l+r>>1;}
void Build();
void Up_Data(){
if(l==r) {sta=Sta(c);return;}
v<=mid?ls->Up_Data():rs->Up_Data();
Push_Up();
}void Push_Up(){sta=ls->sta+rs->sta;}
Sta Query(){
if(s<=l && t>=r) return sta;
if(s<=mid && t>mid) return ls->Query()+rs->Query();
return s<=mid?ls->Query():rs->Query();
}
}*root,mp[MAXN<<2]; int cnt=0;
SGT* New(int l,int r){
mp[cnt]=SGT(l,r);
return &mp[cnt++];
}void SGT::Build(){
if(l==r) {sta=Sta(read());return;}
(ls=New(l ,mid))->Build();
(rs=New(mid+1,r ))->Build();
Push_Up();
}
int main(){
int n=read();
(root=New(1,n))->Build();
int m=read();
while(m--){
int op=read();
if(op) s=read(),t=read(),printf("%d\n",root->Query().mmax);
else v=read(),c=read(),root->Up_Data();
}
return 0;
}
GSS4:
题目大意:
给定一个序列,支持对某区间所有元素开根号(下取整)的操作,查询某区间内元素和
题解:
注意到一个数连续开根号后会变为1,我们直接暴力修改就行,修改前判断某区间的和是否等于区间长度,相等的话就不用修改,在修改时,可以使用并查集将已经变为1的连在一起,直接跳过,具体实现可以参考代码
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=int(1e5+5);
int n;
LL a[MAXN],tree[MAXN];
int readint(){
int r=0;char c;
while(!isdigit(c=getchar()));
while(r=r*10+c-'0',isdigit(c=getchar()));
return r;
}LL read(){
LL r=0;char c;
while(!isdigit(c=getchar()));
while(r=r*10+c-'0',isdigit(c=getchar()));
return r;
}
int p[MAXN];
void Init() {for(int i=1;i<=n+1;i++) p[i]=i;}
int P(int x) {return x==x?x:p[x]=P(x);}
void Add(int i,LL c) {for(;i<=n;i+=i&(-i)) tree[i]+=c;}
LL Sum(int i) {LL sum=0; for(;i>=1;i-=i&(-i)) sum+=tree[i]; return sum;}
void Change(int l,int r){
if(Sum(r)-Sum(l-1)==r-l+1) return;
for(int i=P(l);i<=r;i=P(i+1)){
if(a[i]^1) {
Add(i,-a[i]),Add(i,a[i]=LL(sqrt(a[i])));
if(a[i]==1) p[i]=i+1;
}
}
}
int main(){
int T=0;
while(scanf("%d",&n)==1){
printf("Case #%d:\n",++T);
memset(tree,0,sizeof tree);
Init();
for(int i=1;i<=n;i++) Add(i,a[i]=read());
int m=readint();
while(m--){
int op=readint(),l=readint(),r=readint();
if(l>r) swap(l,r);
if(op) printf("%lld\n",Sum(r)-Sum(l-1));
else Change(l,r);
}
puts("");
}
return 0;
}
GSS5:
题目大意:
在GSS1的基础上,将查询操作改为在区间
[l,r](l∈[x1,y1],r∈[x2,y2],x1<x2,y1<y2)
中最大的连续和
题解:
只需对GSS1的修改操作稍加改变,进行分类即可,具体可以参考代码
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=int(1e4+5),INF=0xc0c0c0c0;
int num[MAXN];
int read(){
int r=0;char c;bool sign=0;
while(c=getchar(),c=='-'?sign=1:0,!isdigit(c));
while(r=r*10+c-'0',isdigit(c=getchar()));
return sign?-r:r;
}struct Sta{
int lmax,rmax,mmax,sum;
Sta(int x=0){lmax=rmax=mmax=sum=x;}
Sta operator + (const Sta& b) const {
Sta c;
c.sum=sum+b.sum;
c.lmax=max(lmax,sum+b.lmax);
c.rmax=max(b.rmax,b.sum+rmax);
c.mmax=max(max(mmax,b.mmax),rmax+b.lmax);
return c;
}
};struct SGT{
SGT *ls,*rs;
int l,r,mid;
Sta sta;
SGT(){}
SGT(int l,int r):ls(0x0),rs(0x0),l(l),r(r){mid=l+r>>1;}
void Build();
void Push_Up() {sta=ls->sta+rs->sta;}
Sta Query(int s,int t){
if(s>t) return Sta();
if(s<=l && t>=r) return sta;
if(s<=mid && t>mid) return ls->Query(s,t)+rs->Query(s,t);
return s<=mid?ls->Query(s,t):rs->Query(s,t);
}
}*root,mp[MAXN<<5];int cnt=0;
SGT* New(int l,int r){
mp[cnt]=SGT(l,r);
return &mp[cnt++];
}void SGT::Build(){
if(l==r) {sta=Sta(num[l]);return;}
(ls=New( l,mid))->Build();
(rs=New(mid+1, r))->Build();
Push_Up();
}
int main(){
int T=read();
while(T--){
int n=read();
for(int i=1;i<=n;i++) num[i]=read();
(root=New(1,n))->Build();
int m=read();
while(m--){
int a=read(),b=read(),x=read(),y=read(),_max=INF;
if(b<x) _max=root->Query(a,b).rmax+root->Query(b+1,x-1).sum+root->Query(x,y).lmax;
else
_max=max(_max,root->Query(a,x).rmax+root->Query(x,y).lmax-num[x]),
_max=max(_max,root->Query(a,b).rmax+root->Query(b,y).lmax-num[b]),
_max=max(_max,root->Query(x,b).mmax);//QAQ 这里之前写反了...
printf("%d\n",_max);
}
}
return 0;
}
GSS6:
题目大意:
在GSS3的基础上加上插入与删除操作
题解:
用Splay维护序列即可
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=int(1e5+5),INF=0xc0c0c0c0;
int n;
int a[MAXN];
int read(){
int r=0;char c;bool sign=0;
while(c=getchar(),c=='-'?sign=1:0,!isdigit(c));
while(r=r*10+c-'0',isdigit(c=getchar()));
return sign?-r:r;
}
#define ls s[0]
#define rs s[1]
struct Node{
Node *p,*s[2];
int lmax,rmax,mmax,sum,x,sz;
Node(){}
Node(int x);
int lr() {return p->rs==this;}
Node* Link(int d,Node* p);
void Push_Up(){
sz=ls->sz+1+rs->sz;
sum=ls->sum+x+rs->sum;
lmax=max(ls->lmax,ls->sum+x+max(0,rs->lmax));
rmax=max(rs->rmax,rs->sum+x+max(0,ls->rmax));
mmax=max(max(0,ls->rmax)+x+max(0,rs->lmax),max(ls->mmax,rs->mmax));
}
}*null=new Node(INF),*root,node[MAXN<<1];
stack<Node*> mp;
Node* New(int x){
Node *p=mp.top();mp.pop();
*p=Node(x);
return p;
}void Del(Node *p) {mp.push(p);}
Node::Node(int x){
p=ls=rs=null;
sz=null?1:0;
lmax=rmax=mmax=x;
this->x=sum=x^INF?x:0;
}Node* Node::Link(int d,Node *p) {s[d]=p;return p==null?this:p->p=this;}
void Rtt(Node* o){
Node *p=o->p,*g=p->p;
int d=o->lr();
o->Link(d^1,p->Link(d,o->s[d^1]));
p->Push_Up();
g==null?(o->p=null,root=o):g->Link(g->rs==p,o);
}void Splay(Node *p,Node *tar){
while(p->p!=tar&&p->p->p!=tar)
p->lr()==p->p->lr()?(Rtt(p->p),Rtt(p)):(Rtt(p),Rtt(p));
if(p->p!=tar) Rtt(p);
p->Push_Up();
}void Find(int k,Node *tar){
Node *p=root;
for(int d=p->ls->sz;(d+1)^k;d=p->ls->sz)
k<=d?p=p->ls:(k-=d+1,p=p->rs);
Splay(p,tar);
}Node* Build(int l,int r){
if(l==r) return New(a[l]);
int mid=l+r>>1;
Node *p=New(a[mid]);
l<mid?p->Link(0,Build(l,mid-1)):0;
r>mid?p->Link(1,Build(mid+1,r)):0;
return p->Push_Up(),p;
}void Init(){
n=read();
for(int i=0;i<n<<1;i++) mp.push(&node[i]);
for(int i=1;i<=n;i++) a[i]=read();
root=New(0);
Node *p=New(0);
root->Link(1,p->Link(0,Build(1,n)));
p->Push_Up(); root->Push_Up();
}
#define ans root->rs->ls
int main(){
Init();
int m=read();
while(m--){
char op[3];
int l;
scanf("%s",op);
switch (op[0]){
case 'I':Find(l=read(),null);Find(l+1,root);
root->rs->Link(0,New(read()));root->rs->Push_Up();root->Push_Up();
break;
case 'D':Find(l=read(),null);Find(l+2,root);
Del(ans);ans=null;root->rs->Push_Up();root->Push_Up();
break;
case 'R':Find(read()+1,null);root->x=read();root->Push_Up(); break;
case 'Q':Find(read(),null);Find(read()+2,root);printf("%d\n",ans->mmax); break;
}
}
return 0;
}
GSS7:
题目大意:
将GSS1扔到树上…
题解:
树剖orLink/Cut Tree
不过窝建议没有受虐倾向还是不要写树剖的好,由于树剖查询时链不是连续的,所以合并时很麻烦且易错…
反正窝树剖写了5k,调了三晚上,Link/Cut Tree 3k,写了1h左右…
Link/Cut Tree代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=int(1e5+5),INF=39980641;
int read(){
int r=0;char c;bool sign=0;
while(c=getchar(),c=='-'?sign=1:0,!isdigit(c));
while(r=r*10+c-'0',isdigit(c=getchar()));
return sign?-r:r;
}
#define ls s[0]
#define rs s[1]
struct Node{
Node *p,*s[2];
int lmax,rmax,mmax,sum,x;
int set,rev,sz;
Node(){}
Node(int _);
int lr() {return p->rs==this;}
int In() {return p->rs==this||p->ls==this;}
Node *Link(int d,Node *p);
void Push_Up(){
sz=ls->sz+1+rs->sz;
lmax=max(ls->lmax,ls->sum+x+max(0,rs->lmax));
rmax=max(rs->rmax,rs->sum+x+max(0,ls->rmax));
sum=ls->sum+x+rs->sum;
mmax=max(max(ls->mmax,rs->mmax),max(0,ls->rmax)+x+max(0,rs->lmax));
}
void Rev();
void Set(int c);
void Push_Down();
}*null=new Node(INF),tree[MAXN];
Node::Node(int _){
p=ls=rs=null;
null?(sz=1,lmax=rmax=mmax=sum=x=_):(sz=sum=x=0,lmax=rmax=mmax=-INF);
set=INF;rev=0;
}Node* Node::Link(int d,Node *p) {s[d]=p;return p==null?this:p->p=this;}
void Node::Rev() {if(this==null) return; rev^=1;swap(ls,rs),swap(lmax,rmax);}
void Node::Set(int c) {if(this==null) return; set=x=c;sum=x*sz;lmax=rmax=mmax=max(sum,x);}
void Node::Push_Down(){
if(In()) p->Push_Down();
rev?(ls->Rev(),rs->Rev(),rev=0):0;
set^INF?(ls->Set(set),rs->Set(set),set=INF):0;
}
#define tu (&tree[u])
#define tv (&tree[v])
void Rtt(Node *o){
Node *p=o->p,*g=p->p;
int d=o->lr(),k=p->In();
o->Link(d^1,p->Link(d,o->s[d^1]));
p->Push_Up();
k?g->Link(g->rs==p,o):o->p=g;
}void Splay(Node *p){
p->Push_Down();
while(p->In()&&p->p->In())
p->lr()==p->p->lr()?(Rtt(p->p),Rtt(p)):(Rtt(p),Rtt(p));
if(p->In()) Rtt(p);
p->Push_Up();
}void Access(Node *u){
for(Node *v=null;u!=null;v=u,u=u->p)
Splay(u),u->rs=v,u->Push_Up();
}void Link(){
int u=read(),v=read();
Access(tu);Splay(tu);tu->Rev();
tu->p=tv;
}
void Init(){
int n=read();
for(int u=1;u<=n;u++) tree[u]=Node(read());
n--;
while(n--) Link();
}void Query(){
int u=read(),v=read();
Access(tu);Splay(tu);tu->Rev();
Access(tv);Splay(tv);
printf("%d\n",max(0,tv->mmax));
}void Change(){
int u=read(),v=read();
Access(tu);Splay(tu);tu->Rev();
Access(tv);Splay(tv);
tv->Set(read());
}
int main(){
Init();
int m=read();
while(m--){
int op=read();
if(op==1) Query();
else Change();
}
return 0;
}
树剖代码:
#include <bits/stdc++.h>
using namespace std;
int const MAXN=int(1e5+5),INF=39980641;
int s,t,c,idx=1;
int a[MAXN];
vector<int> g[MAXN];
int pos[MAXN],ipos[MAXN],top[MAXN],p[MAXN],dep[MAXN],siz[MAXN],son[MAXN];
int read(){
int r=0;char c;bool sign=0;
while(c=getchar(),c=='-'?sign=1:0,!isdigit(c));
while(r=r*10+c-'0',isdigit(c=getchar()));
return sign?-r:r;
}
struct Sta{
int lmax,rmax,mmax,sum;
Sta(int x=0) {x^INF?(lmax=rmax=mmax=sum=x):(lmax=rmax=mmax=-INF,sum=x=0);}
Sta operator + (const Sta& b) const {
Sta c;
c.sum=sum+b.sum;
c.lmax=max(lmax,sum+b.lmax);
c.rmax=max(b.rmax,b.sum+rmax);//这里错一发...
c.mmax=max(max(mmax,b.mmax),rmax+b.lmax);
return c;
}
};Sta Rev(Sta sta) {swap(sta.lmax,sta.rmax);return sta;}
struct SGT{
SGT *ls,*rs;
int l,r,mid,set;
Sta sta;
SGT(){}
SGT(int l,int r):ls(0x0),rs(0x0),l(l),r(r){mid=l+r>>1;set=INF;}
void Build();
void Set(int c) {sta.sum=(r-l+1)*c;sta.lmax=sta.rmax=sta.mmax=max(c,sta.sum);set=c;}//更新错误一发...
void Push_Up() {sta=ls->sta+rs->sta;}
void Push_Down() {set^INF?(ls->Set(set),rs->Set(set),set=INF):0;}
void Up_Data(){
if(s<=l&&t>=r) {Set(c);return;}
Push_Down();
if(s<=mid) ls->Up_Data();
if(t> mid) rs->Up_Data();
Push_Up();
}Sta Query(){
if(s<=l&&t>=r) return sta;
Push_Down();
if(s<=mid&&t>mid) return ls->Query()+rs->Query();
return s<=mid?ls->Query():rs->Query();
}
}*root,mp[MAXN<<1];int cnt=0;
SGT* New(int l,int r) {mp[cnt]=SGT(l,r);return &mp[cnt++];}
void SGT::Build(){
if(l==r) {sta=Sta(a[ipos[l]]);return;}
(ls=New(l,mid))->Build();
(rs=New(mid+1,r))->Build();
Push_Up();//忘上传错一发...QAQ
}
void Add(int u,int v) {g[u].push_back(v);g[v].push_back(u);}
void DFS_1(int u){
son[u]=0;siz[u]=1;
for(int i=0;i<g[u].size();i++){
int v=g[u][i];
if(v==p[u]) continue;
p[v]=u;dep[v]=u+1;
DFS_1(v);
siz[u]+=siz[v];
siz[v]>siz[son[u]]?son[u]=v:0;
}
}void DFS_2(int u,int t){
ipos[pos[u]=idx++]=u;top[u]=t;
if(son[u]) DFS_2(son[u],t);
for(int i=0;i<g[u].size();i++){
int v=g[u][i];
if(v==son[u]||v==p[u]) continue;
DFS_2(v,v);
}
}void Init(){
int n=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<n;i++) Add(read(),read());
dep[1]=1;
DFS_1(1);DFS_2(1,1);
(root=New(1,n))->Build();
}
int Query(){
int u=read(),v=read(),d=0;
Sta sta[2];
sta[0]=sta[1]=Sta(INF);
for(int fu=top[u],fv=top[v];fu^fv;fu=top[u=p[fu]]){
if(dep[fu]<dep[fv]) swap(u,v),swap(fu,fv),d^=1;;
s=pos[fu],t=pos[u];
sta[d]=d?root->Query()+sta[d]:sta[d]+Rev(root->Query());
}
if(dep[u]>dep[v]) swap(u,v); else d^=1;
s=pos[u],t=pos[v];
sta[d]=d?root->Query()+sta[d]:sta[d]+Rev(root->Query());
return (sta[0]+sta[1]).mmax;
}void Up_Data(){
int u=read(),v=read();c=read();
for(int fu=top[u],fv=top[v];fu^fv;fu=top[u=p[fu]]){
if(dep[fu]<dep[fv]) swap(u,v),swap(fu,fv);
s=pos[fu],t=pos[u];
root->Up_Data();
}
if(dep[u]>dep[v]) swap(u,v);
s=pos[u],t=pos[v];
root->Up_Data();
}
int main(){
Init();
int m=read();
while(m--){
int op=read();
if(op==1) printf("%d\n",max(0,Query()));
else Up_Data();
}
return 0;
}
GSS8:
题目大意:
在GSS6的基础上把元素的范围扩大了…
题解:
窝还没写,估计会卡常?先挖个坑…