zoj 5823 Soldier Game 2018 青岛

题意:现在有n个人,现在可以把这n个人分成若干组,只有连续的人才能被分为一组,并且一个组内最多2个人,现在问你 所有组内的最大值-最小值 这个差值最小是多少。

题解:

将每个人的情况3种情况都拿出来,把这些所有的情况从小到大排序,然后我们枚举起点,然后一直不停的添加线段,然后直到当前的区间内的所有线段,我们可以选择其中的一部分,使得这些线段能够不重合的前提下巧好覆盖1-n的区间内。

tree[x] 假设管理的区间为 [l, r]  tree[x][i][j] i代表的是左端点 j 代表的是右端点, 当i == 1 的时候,j == 1的时候,我们管理的是 [l+1,r+1]这个区间的状态 i == 0,j == 0 管理的是 [l, r]这个区间的状态。

所以我们pushup的时候不重合的搞就好了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod =  (int)1e9+7;
const int N = 1e5 + 100;
int a[N][2];
pll p[N<<1];
bool cmp(pll & x, pll & y){
    return a[x.fi][x.se] < a[y.fi][y.se];
}
int tree[N<<2][2][2];
void Build(int l, int r, int rt){
    tree[rt][0][0] = tree[rt][0][1] = tree[rt][1][0] = tree[rt][1][1] = 0;
    if(l == r) {
        tree[rt][1][0] = 1;
        return ;
    }
    int m = l+r >> 1;
    Build(lson); Build(rson);
}
void PushUp(int rt){
    tree[rt][0][0] = (tree[rt<<1][0][0] && tree[rt<<1|1][0][0]) || (tree[rt<<1][0][1] && tree[rt<<1|1][1][0]);
    tree[rt][0][1] = (tree[rt<<1][0][0] && tree[rt<<1|1][0][1]) || (tree[rt<<1][0][1] && tree[rt<<1|1][1][1]);
    tree[rt][1][0] = (tree[rt<<1][1][0] && tree[rt<<1|1][0][0]) || (tree[rt<<1][1][1] && tree[rt<<1|1][1][0]);
    tree[rt][1][1] = (tree[rt<<1][1][1] && tree[rt<<1|1][1][1]) || (tree[rt<<1][1][0] && tree[rt<<1|1][0][1]);
}
void Update(int L, int op,int l, int r, int rt){
    if(l == r){
        tree[rt][0][op] ^= 1;
        return ;
    }
    int m = l+r >> 1;
    if(L <= m) Update(L, op, lson);
    else Update(L, op, rson);
    PushUp(rt);
}
int main(){
    int T, n;
    scanf("%d", &T);
    while(T--){
        scanf("%d", &n);
        int m = 0;
        for(int i = 1; i <= n; ++i){
            scanf("%d", &a[i][0]);
            p[++m] = pll(i,0);
            if(i-1) {
                a[i-1][1] = a[i-1][0] + a[i][0];
                p[++m] = pll(i-1,1);
            }
        }
        sort(p+1, p+1+m, cmp);
        Build(1,n,1);
        LL ans = INF;
        for(int i = 1, j=1; i <= m; ++i){
            while(j <= m && !tree[1][0][0]){
                Update(p[j].fi, p[j].se, 1, n, 1);
                j++;
            }
            if(tree[1][0][0]) ans = min(ans, 1ll*a[p[j-1].fi][p[j-1].se] - a[p[i].fi][p[i].se]);
            Update(p[i].fi, p[i].se, 1, n, 1);
        }
        printf("%lld\n", ans);
    }
    return 0;
}

转载别的大神的

猜你喜欢

转载自blog.csdn.net/mlm5678/article/details/84452239