首页 > 代码库 > ZOJ 2301 / HDU 1199 Color the Ball 离散化+线段树区间连续最大和

ZOJ 2301 / HDU 1199 Color the Ball 离散化+线段树区间连续最大和

题意:给你n个球排成一行,初始都为黑色,现在给一些操作(L,R,color),给[L,R]区间内的求染上颜色color,‘w‘为白,‘b‘为黑。问最后最长的白色区间的起点和终点的位置。

解法:先离散化,为了防止离散后错误,不仅将L,R离散,还要加入L+1,L-1,R+1,R-1一起离散,这样就绝不会有问题了。然后建线段树,线段树维护四个值:

1.col  区间颜色  0 表示黑  1 表示白  -1表示无标记

2.maxi 区间内最大白区间的长度,由于白色用1表示,所以最大白区间的长度即为区间最大连续和

3.lmax 从区间左端开始的最大白区间长度

4.rmax 从区间右端开始的最大白区间长度

然后更新,查询,就跟普通求区间连续最大和无异了

代码:

#include <iostream>#include <cmath>#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <algorithm>#include <map>using namespace std;#define N 14007struct node{    int lmax,rmax,maxi,col;}tree[4*N];int num[N],x[N];int L[2005],R[2005];char ss[2005][3];map<int,int> mp;void pushup(int l,int r,int rt){    tree[rt].lmax = tree[2*rt].lmax;    tree[rt].rmax = tree[2*rt+1].rmax;    tree[rt].maxi = max(max(tree[2*rt].maxi,tree[2*rt+1].maxi),tree[2*rt].rmax+tree[2*rt+1].lmax);    int mid = (l+r)/2;    int L = x[mid]-x[l-1];  //真实的长度    int R = x[r]-x[mid];    if(tree[2*rt].lmax == L)        tree[rt].lmax += tree[2*rt+1].lmax;    if(tree[2*rt+1].rmax == R)        tree[rt].rmax += tree[2*rt].rmax;}void pushdown(int l,int r,int rt){    if(tree[rt].col != -1)    {        tree[2*rt].col = tree[2*rt+1].col = tree[rt].col;        int mid = (l+r)/2;        int L = x[mid]-x[l-1];        int R = x[r]-x[mid];        tree[2*rt].maxi = tree[2*rt].lmax = tree[2*rt].rmax = L*tree[rt].col;        tree[2*rt+1].maxi = tree[2*rt+1].lmax = tree[2*rt+1].rmax = R*tree[rt].col;        tree[rt].col = -1;    }}void build(int l,int r,int rt){    tree[rt].maxi = tree[rt].lmax = tree[rt].rmax = 0;    tree[rt].col = -1;    if(l == r) return;    int mid = (l+r)/2;    build(l,mid,2*rt);    build(mid+1,r,2*rt+1);}void update(int l,int r,int aa,int bb,int col,int rt){    if(aa <= l && bb >= r)    {        tree[rt].col = col;        tree[rt].maxi = tree[rt].lmax = tree[rt].rmax = col*(x[r]-x[l-1]);        return;    }    pushdown(l,r,rt);    int mid = (l+r)/2;    if(aa <= mid)        update(l,mid,aa,bb,col,2*rt);    if(bb > mid)        update(mid+1,r,aa,bb,col,2*rt+1);    pushup(l,r,rt);}int query(int l,int r,int rt){    if(l == r) return x[l];    int mid = (l+r)/2;    pushdown(l,r,rt);    if(tree[2*rt].maxi == tree[1].maxi)   //tree[1]  not  tree[rt]        return query(l,mid,2*rt);    else if(tree[2*rt].rmax+tree[2*rt+1].lmax == tree[1].maxi)        return x[mid]-tree[2*rt].rmax+1;    else        return query(mid+1,r,2*rt+1);}int main(){    int n,i,j,k;    while(scanf("%d",&n)!=EOF)    {        mp.clear();        for(i=1;i<=n;i++)        {            scanf("%d%d%s",&L[i],&R[i],ss[i]);            num[6*i-5] = L[i]-1;            num[6*i-4] = L[i];            num[6*i-3] = L[i]+1;            num[6*i-2] = R[i]-1;            num[6*i-1] = R[i];            num[6*i] = R[i]+1;        }        sort(num+1,num+6*n+1);        int ind = unique(num+1,num+6*n+1)-num-1;        int now = 0;        x[0] = 0;        for(i=1;i<=ind;i++)        {            x[++now] = num[i];            mp[num[i]] = now;        }        build(1,now,1);        for(i=1;i<=n;i++)        {            int ka = mp[L[i]];            int kb = mp[R[i]];            if(ss[i][0] == w)                update(1,now,ka,kb,1,1);            else                update(1,now,ka,kb,0,1);        }        if(tree[1].maxi <= 0)            puts("Oh, my god");        else        {            int left = query(1,now,1);            int right = left+tree[1].maxi-1;            printf("%d %d\n",left,right);        }    }    return 0;}
View Code

 

ZOJ 2301 / HDU 1199 Color the Ball 离散化+线段树区间连续最大和