像我这么弱的人真的该码点儿代码了TAT
不然会被学弟虐哭TAT
GSS1
题目大意:给出一个序列,每次询问 [l,r] 内的最大连续子段和
线段树维护区间最值(左、右、区间最大
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
#define N 50005
using namespace std;
int n,m,l,r,L,M,R,S;
int a[N];
int T[N<<2],lm[N<<2],mx[N<<2],rm[N<<2];
void build(int v,int l,int r)
{
if (l==r)
{
T[v]=mx[v]=lm[v]=rm[v]=a[l];
return;
}
int mid=l+r>>1,lc=v<<1,rc=v<<1|1;
build(lc,l,mid);
build(rc,mid+1,r);
lm[v]=max(lm[lc],T[lc]+lm[rc]);
mx[v]=max(max(mx[lc],mx[rc]),rm[lc]+lm[rc]);
rm[v]=max(rm[rc],T[rc]+rm[lc]);
T[v]=T[lc]+T[rc];
}
void query(int v,int l,int r,int x,int y,int &L,int &M,int &R,int &S)
{
if (x<=l&&r<=y)
{
L=lm[v],M=mx[v],R=rm[v],S=T[v];
return;
}
int mid=l+r>>1;
if (y<=mid) query(v<<1,l,mid,x,y,L,M,R,S);
else if (mid<x) query(v<<1|1,mid+1,r,x,y,L,M,R,S);
else
{
int L1,M1,R1,S1,L2,M2,R2,S2;
query(v<<1,l,mid,x,y,L1,M1,R1,S1);
query(v<<1|1,mid+1,r,x,y,L2,M2,R2,S2);
L=max(L1,S1+L2);
M=max(max(M1,M2),R1+L2);
R=max(R2,S2+R1);
S=S1+S2;
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,1,n);
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
scanf("%d%d",&l,&r);
query(1,1,n,l,r,L,M,R,S);
printf("%d\n",M);
}
return 0;
}
GSS2
GSS1中连续子段和,重复数字只算一次
坑哭辣。。。(还是我弱。。。TATATAT
只有询问,就可以离线 =_=
按询问的右端点升序排序
先考虑设 a[i] 表示 i 到当前位置的和
当新插入一个数 x 的时候,其实就是 last[x] + 1 到当前位置都加上 x
我们需要的是区间的历史最大值
明显线段树可以搞嘛QAQ
(维护当前区间最大,历史区间最大,标记增加总量和增加的最大值
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
#define N 100005
#define LL long long
using namespace std;
int n,m,x,y,D = 100000;
int first[N],next[N],to[N],a[N],last[N << 1];
LL mx[N<<2],now[N<<2],add[N<<2],amx[N<<2],ans[N];
void inser(int x,int y,int siz)
{
next[siz] = first[x];
first[x] = siz;
to[siz] = y;
}
void push_down(int v)
{
int lc = v << 1,rc = lc | 1;
amx[lc] = max(amx[lc],add[lc] + amx[v]),add[lc] += add[v];
amx[rc] = max(amx[rc],add[rc] + amx[v]),add[rc] += add[v];
mx[lc] = max(mx[lc],now[lc] + amx[v]),now[lc] += add[v];
mx[rc] = max(mx[rc],now[rc] + amx[v]),now[rc] += add[v];
add[v] = 0,amx[v] = -1e15;
}
void modify(int v,int l,int r,int x,int y)
{
if (l == r) {mx[v] = now[v] = y;return;}
int mid = l + r >> 1;
push_down(v);
if (x <= mid) modify(v << 1,l,mid,x,y);
else modify(v << 1 | 1,mid + 1,r,x,y);
mx[v] = max(mx[v << 1],mx[v << 1 | 1]);
now[v] = max(now[v << 1],now[v << 1 | 1]);
}
void Add(int v,int l,int r,int x,int y,int c)
{
if (x <= l && r <= y)
{
now[v] += c;
mx[v] = max(mx[v],now[v]);
add[v] += c;
amx[v] = max(amx[v],add[v]);
return;
}
int mid = l + r >> 1;
push_down(v);
if (x <= mid) Add(v << 1,l,mid,x,y,c);
if (mid < y) Add(v << 1 | 1,mid + 1,r,x,y,c);
now[v] = max(now[v << 1],now[v << 1 | 1]);
mx[v] = max(mx[v << 1],mx[v << 1| 1]);
}
LL query(int v,int l,int r,int x,int y)
{
if (x <= l && r <= y) return mx[v];
int mid = l + r >> 1;LL ret = -1e15;
push_down(v);
if (x <= mid) ret = max(ret,query(v << 1,l,mid,x,y));
if (mid < y) ret = max(ret,query(v << 1 | 1,mid + 1,r,x,y));
return ret;
}
int main()
{
scanf("%d",&n);
for (int i = 1;i <= n;i ++) scanf("%d",&a[i]);
for (int i = 1;i < n<<2;i ++) mx[i] = amx[i] = now[i] = -1e15;
scanf("%d",&m);
for (int i = 1;i <= m;i ++)
{
scanf("%d%d",&x,&y);
inser(y,x,i);
}
for (int i = 1;i <= n;i ++)
{
modify(1,1,n,i,a[i]);
if (last[a[i] + D] + 1 < i) Add(1,1,n,last[a[i] + D] + 1,i - 1,a[i]);
last[a[i] + D] = i;
for (int j = first[i];j;j = next[j])
ans[j] = query(1,1,n,to[j],i);
}
for (int i = 1;i <= m;i ++) printf("%lld\n",max(0ll,ans[i]));
return 0;
}
GSS3
GSS1加单点修改。。。
好像没有什么区别。。。
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
#define N 50005
using namespace std;
int n,m,opt,l,r,L,M,R,S;
int a[N];
int T[N<<2],lm[N<<2],mx[N<<2],rm[N<<2];
void update(int v)
{
int lc=v<<1,rc=v<<1|1;
lm[v]=max(lm[lc],T[lc]+lm[rc]);
mx[v]=max(max(mx[lc],mx[rc]),rm[lc]+lm[rc]);
rm[v]=max(rm[rc],T[rc]+rm[lc]);
T[v]=T[lc]+T[rc];
}
void build(int v,int l,int r)
{
if (l==r)
{
T[v]=mx[v]=lm[v]=rm[v]=a[l];
return;
}
int mid=l+r>>1;
build(v<<1,l,mid);
build(v<<1|1,mid+1,r);
update(v);
}
void modify(int v,int l,int r,int x,int y)
{
if (l==r)
{
T[v]=mx[v]=lm[v]=rm[v]=y;
return;
}
int mid=l+r>>1;
if (x<=mid) modify(v<<1,l,mid,x,y);
else modify(v<<1|1,mid+1,r,x,y);
update(v);
}
void query(int v,int l,int r,int x,int y,int &L,int &M,int &R,int &S)
{
if (x<=l&&r<=y)
{
L=lm[v],M=mx[v],R=rm[v],S=T[v];
return;
}
int mid=l+r>>1;
if (y<=mid) query(v<<1,l,mid,x,y,L,M,R,S);
else if (mid<x) query(v<<1|1,mid+1,r,x,y,L,M,R,S);
else
{
int L1,M1,R1,S1,L2,M2,R2,S2;
query(v<<1,l,mid,x,y,L1,M1,R1,S1);
query(v<<1|1,mid+1,r,x,y,L2,M2,R2,S2);
L=max(L1,S1+L2);
M=max(max(M1,M2),R1+L2);
R=max(R2,S2+R1);
S=S1+S2;
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,1,n);
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&opt,&l,&r);
if (opt)
{
query(1,1,n,l,r,L,M,R,S);
printf("%d\n",M);
}
else
modify(1,1,n,l,r);
}
return 0;
}
GSS4
给定一个序列,一种操作:将区间内的每个数开方,每次询问区间和
开方次数就那么多,暴力搞就可以了
坑:题目没有说 l<=r。。。
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
#define N 100005
#define LL long long
using namespace std;
int n,m,C,opt,x,y;
LL a[N],T[N<<2];
bool tag[N<<2];
void build(int v,int l,int r)
{
if (l==r)
{
tag[v]=a[l]<=1;
T[v]=a[l];
return;
}
int mid=l+r>>1;
build(v<<1,l,mid);
build(v<<1|1,mid+1,r);
T[v]=T[v<<1]+T[v<<1|1];
tag[v]=tag[v<<1]&&tag[v<<1|1];
}
LL query(int v,int l,int r)
{
if (x<=l&&r<=y) return T[v];
int mid=l+r>>1;LL ret=0;
if (x<=mid) ret+=query(v<<1,l,mid);
if (mid<y) ret+=query(v<<1|1,mid+1,r);
return ret;
}
void modify(int v,int l,int r)
{
if (tag[v]) return;
if (l==r)
{
T[v]=sqrt(T[v]);
tag[v]=T[v]<=1;
return;
}
int mid=l+r>>1;
if (x<=mid) modify(v<<1,l,mid);
if (mid<y) modify(v<<1|1,mid+1,r);
T[v]=T[v<<1]+T[v<<1|1];
tag[v]=tag[v<<1]&&tag[v<<1|1];
}
int main()
{
while (~scanf("%d",&n))
{
printf("Case #%d:\n",++C);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n);
scanf("%d",&m);
while (m--)
{
scanf("%d%d%d",&opt,&x,&y);
if (x>y) swap(x,y);
if (opt) printf("%lld\n",query(1,1,n));
else modify(1,1,n);
}
puts("");
}
return 0;
}
GSS5
GSS1的序列中,要求左端点 i 满足 x1<=i<=y1,右端点 j 满足 x2<=j<=y2,其中 x1<=y1,x2<=y2,x1<=x2,y1<=y2
分类讨论就好。。。
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<string>
#define N 10005
using namespace std;
int n,m,x1,x2,y1,y2,a,b,c,d,ans,L,M,R,S;
int A[N];
int T[N<<2],lm[N<<2],rm[N<<2],mx[N<<2];
void build(int v,int l,int r)
{
if (l==r)
{
T[v]=lm[v]=rm[v]=mx[v]=A[l];
return;
}
int mid=l+r>>1,lc=v<<1,rc=v<<1|1;
build(lc,l,mid);
build(rc,mid+1,r);
T[v]=T[lc]+T[rc];
lm[v]=max(lm[lc],T[lc]+lm[rc]);
rm[v]=max(rm[rc],T[rc]+rm[lc]);
mx[v]=max(rm[lc]+lm[rc],max(mx[lc],mx[rc]));
}
void query(int v,int l,int r,int x,int y,int &L,int &M,int &R,int &S)
{
if (x<=l&&r<=y)
{
L=lm[v],M=mx[v],R=rm[v],S=T[v];
return;
}
int mid=l+r>>1;
if (y<=mid) query(v<<1,l,mid,x,y,L,M,R,S);
else if (mid<x) query(v<<1|1,mid+1,r,x,y,L,M,R,S);
else
{
int L1,M1,R1,S1,L2,M2,R2,S2;
query(v<<1,l,mid,x,y,L1,M1,R1,S1);
query(v<<1|1,mid+1,r,x,y,L2,M2,R2,S2);
S=S1+S2;
L=max(L1,S1+L2);
R=max(R2,S2+R1);
M=max(R1+L2,max(M1,M2));
}
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&A[i]);
build(1,1,n);
for (int i=2;i<=n;i++) A[i]+=A[i-1];
scanf("%d",&m);
while (m--)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
if (y1<x2)
{
query(1,1,n,x1,y1,L,M,R,S),a=R;
query(1,1,n,x2,y2,L,M,R,S),a+=L;
printf("%d\n",a+A[x2-1]-A[y1]);
}
else
{
a=b=c=d=0;ans=-1e9;
if (x1^x2) query(1,1,n,x1,x2-1,L,M,R,S),a=max(a,R);
query(1,1,n,x2,y1,L,M,R,S),ans=max(a+L,M),b=S,c=R;
if (y1^y2) query(1,1,n,y1+1,y2,L,M,R,S),d=max(d,L);
ans=max(ans,max(a+b+d,c+d));
printf("%d\n",ans);
}
}
}
return 0;
}
GSS6
在 GSS1 的基础上增加了操作:插入、删除、替换
嘿嘿,可以用 splay 了嘛~
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<string>
#define lc(x) son[x][0]
#define rc(x) son[x][1]
#define N 200005
#define INF 1000000001
using namespace std;
int n,m,root,x,y,l,r,a[N];
int son[N][2],fa[N],size[N],sum[N],lm[N],rm[N],mx[N],key[N];
char opt[2];
void update(int x)
{
int lc = lc(x),rc = rc(x);
sum[x] = sum[lc] + sum[rc] + key[x];
lm[x] = max(lm[lc],sum[lc] + key[x] + max(lm[rc],0));
rm[x] = max(rm[rc],sum[rc] + key[x] + max(rm[lc],0));
mx[x] = max(key[x] + max(max(rm[lc],lm[rc]),max(0,lm[rc] + rm[lc])),max(mx[lc],mx[rc]));
size[x] = size[lc] + size[rc] + 1;
}
int build(int l,int r)
{
int m = l+r >> 1;
key[m] = a[m];
if (l ^ m) lc(m) = build(l,m - 1),fa[lc(m)] = m;
if (m ^ r) rc(m) = build(m + 1,r),fa[rc(m)] = m;
update(m);
return m;
}
void rotate(int x)
{
int y = fa[x],g = fa[y],t = lc(y) == x;
son[y][t ^ 1] = son[x][t];
if (son[x][t]) fa[son[x][t]] = y;
if (g) son[g][rc(g) == y] = x;
fa[x] = g;
son[x][t] = y;
fa[y] = x;
update(y);
}
void splay(int x,int rt)
{
if (x == rt || !x) return;
while (fa[x] ^ rt)
{
int y = fa[x];
if (fa[y] ^ rt)
rotate((lc(y) == x ^ lc(fa[y]) == y)? x : y);
rotate(x);
}
update(x);
if (!rt) root = x;
}
int findkth(int k)
{
int x = root;
while (true)
{
if (size[lc(x)] + 1 == k) return x;
if (size[lc(x)] >= k) x = lc(x);
else k -= size[lc(x)] + 1,x = rc(x);
}
}
int main()
{
scanf("%d",&n);
lm[0] = rm[0] = mx[0] = -INF;
for (int i = 1;i <= n;i ++) scanf("%d",&a[i + 1]);
root = build(1,n += 2);
scanf("%d",&m);
while (m --)
{
scanf("%s%d",opt,&x);
if (opt[0] != 'D') scanf("%d",&y);
switch (opt[0])
{
case 'I':
splay(r = findkth(x + 1),0),splay(l = findkth(x),root);
key[++ n] = y;
fa[rc(l) = n] = l;
update(n),update(l),update(r);
break;
case 'D':
splay(r = findkth(x + 2),0),splay(l = findkth(x),root);
rc(l) = 0;
update(l),update(r);
break;
case 'R':
splay(l = findkth(x + 1),0);
key[l] = y;
update(l);
break;
case 'Q':
splay(r = findkth(y + 2),0),splay(l = findkth(x),root);
printf("%d\n",mx[rc(l)]);
break;
}
}
return 0;
}
GSS7
序列改为树上的链
可以写树链剖分TAT
我用的 LCT…
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<string>
#define lc(x) son[x][0]
#define rc(x) son[x][1]
#define N 200005
#define INF 1000000001
using namespace std;
int n,m,q,siz,top,opt,x,y,w;
int first[N],next[N],to[N],st[N],a[N];
int fa[N],son[N][2],key[N],size[N],cov[N],rev[N],lm[N],rm[N],mx[N],sum[N];
bool root[N];
void inser(int x,int y)
{
next[++ siz] = first[x];
first[x] = siz;
to[siz] = y;
}
void dfs(int x)
{
for (int i = first[x];i;i = next[i])
if (to[i] ^ fa[x]) fa[to[i]] = x,dfs(to[i]);
}
void update(int x)
{
int lc = lc(x),rc = rc(x);
sum[x] = sum[lc(x)] + sum[rc(x)] + key[x];
lm[x] = max(lm[lc],sum[lc] + key[x] + max(0,lm[rc]));
rm[x] = max(rm[rc],sum[rc] + key[x] + max(0,rm[lc]));
mx[x] = max(key[x] + max(max(0,lm[rc] + rm[lc]),max(lm[rc],rm[lc])),max(mx[lc],mx[rc]));
size[x] = size[lc(x)] + size[rc(x)] + 1;
}
void recover(int x,int c)
{
if (!x) return;
lm[x] = rm[x] = mx[x] = c > 0 ? c * size[x] : 0;
sum[x] = c * size[x];
cov[x] = key[x] = c;
}
void reverse(int x)
{
if (!x) return;
swap(lc(x),rc(x));
swap(lm[x],rm[x]);
rev[x] ^= 1;
}
void push_down(int x)
{
if (cov[x] ^ INF)
{
recover(lc(x),cov[x]);
recover(rc(x),cov[x]);
cov[x] = INF;
}
if (rev[x])
{
reverse(lc(x));
reverse(rc(x));
rev[x] = 0;
}
}
void relax(int x)
{
for (;!root[x];x = fa[x]) st[++ top] = x;
for (st[++ top] = x;top;top --) push_down(st[top]);
}
void rotate(int x)
{
int y = fa[x],g = fa[y],t = lc(y) == x;
son[y][t ^ 1] = son[x][t];
if (son[x][t]) fa[son[x][t]] = y;
if (!root[y]) son[g][rc(g) == y] = x;
else root[y] = false,root[x] = true;
fa[x] = g;
son[x][t] = y;
fa[y] = x;
update(y);
}
void splay(int x)
{
relax(x);
while (!root[x])
{
int y = fa[x];
if (!root[y])
rotate((lc(y) == x ^ lc(fa[y]) == y) ? x : y);
rotate(x);
}
update(x);
}
int access(int x)
{
int y = 0;
while (x)
{
splay(x);
root[rc(x)] = true;
root[rc(x) = y] = false;
update(y = x);
x = fa[x];
}
return y;
}
void makeroot(int x)
{
access(x);
splay(x);
reverse(x);
}
int main()
{
scanf("%d",&n);
for (int i = 1;i <= n;i ++)
{
scanf("%d",&a[i]);
cov[i] = INF;
root[i] = true;
lm[i] = rm[i] = mx[i] = a[i] > 0 ? a[i] : 0;
size[i] = 1;
key[i] = a[i];
}
for (int i = 1;i < n;i ++)
{
scanf("%d%d",&x,&y);
inser(x,y),inser(y,x);
}
dfs(1);
scanf("%d",&q);
while (q --)
{
scanf("%d%d%d",&opt,&x,&y);
makeroot(y);
access(x);
splay(x);
if (opt == 1)
printf("%d\n",mx[x]);
else
{
scanf("%d",&w);
rm[x] = lm[x] = mx[x] = w > 0 ? w * size[x] : 0;
key[x] = cov[x] = w;
}
}
return 0;
}
咦怎么有8、9。。。
orz曹清华大爷
我蠢 =。= 并且懒 …(嘿嘿…