spoj GSS系列

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/beginendzrq/article/details/51638291

像我这么弱的人真的该码点儿代码了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曹清华大爷
我蠢 =。= 并且懒 …(嘿嘿…

阅读更多
换一批

没有更多推荐了,返回首页