poj3225 Help with Intervals 线段树,成段更新,TLE,求指教。。本人提供测试数据~

13 篇文章 0 订阅
13 篇文章 0 订阅

题目链接:http://poj.org/problem?id=3225

思路:

采用线段树,对线段区间进行0,1标记表示该区间是否包含在集合s内 

U T S ← S ∪ T 即将[l,r]标记为1 
I T S ← S ∩ T 即将-oo~l和r~+oo标记为0,因为是并集,所以并集后的集合s一定在[l,r]内,则在l,r内的集合被标记是什么状态就是什么状态(表示是否属于s),[l,r]外的集合不属于s所以标记为0 
D T S ← S - T  即将[l,r]标记为0,则在[l,r]内被s包含的集合也会标记为0表示不再属于s 
C T S ← T - S  即先将-oo~l,r~+oo标记为0,这部分不属于[l,r]则一定不属于s,然后将[l,r]的标记0/1互换,因为属于s的不再属于s,不属于s的将属于s 
S T S ← S ⊕ T  即属于s的不变,[l,r]中不属于s的(区间)0标记为1,属于s的(区间)1标记为0,所以[l,r]的标记0/1互换 

最后对区间l,r标记时标记将l*2,r*2标记,如果是闭区间则对l*2+1,或r*2-1进行标记,则输出的时候只需判断奇偶就能判断开闭区间 


终于调通了,拿各组数据测试和 HH 大牛的代码比较运行结果都没问题。为此还用 python 写了一段用于随机生成测试数据的代码。提交到POJ上TLE了。于是自己生成大数据自己比较时间,发现的确是比 HH 大牛的代码慢,但不知道怎么优化。。。


我的 TLE 的代码:

///2014.6.5 - 2014.6.7
///poj3225

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define maxn 131072

bool segT[maxn<<2];
bool ud[maxn<<2];  //标记该结点向下的节点是否与该结点是相同的状态(都在S中或都不在S中)
bool in[maxn+1];

void build(int l,int r,int rt){
    memset(segT,false,sizeof(segT));
    memset(in,false,sizeof(in));
    memset(ud,true,sizeof(ud));
}
void PushUp(int rt){
    if( !ud[rt] ){
        segT[rt] = segT[rt<<1] || segT[rt<<1|1];
        if( (segT[rt<<1] == segT[rt<<1|1]) && ud[rt<<1] && ud[rt<<1|1] )
            ud[rt] = true;
    }
}
void PushDown(int rt){
    if( ud[rt] ){
        segT[rt<<1] = segT[rt<<1|1] = segT[rt];
        ud[rt<<1] = ud[rt<<1|1] = true;
        ud[rt] = false;
    }
}
void convert(int l,int r,int rt){  //取反
    if( ud[rt] ){
        if( segT[rt] ) segT[rt] = false;
        else segT[rt] = true;
        return;
    }
    if( l<=r ){
        int m = (l+r)>>1;
        convert(lson);
        convert(rson);
    }
    PushUp(rt);
}
void update(int L,int R,char cmd,int l,int r,int rt){
    PushDown(rt);
    ud[rt] = false;
    if( L<=l && r<=R ){
        if( cmd == 'U' ) segT[rt] = ud[rt] = true;
        if( cmd == 'D' ) segT[rt] = false,ud[rt] = true;
        if( cmd == 'C' || cmd == 'S' ) convert(l,r,rt);
        PushUp(rt);
        return ;
    }
    if( l==r ) return ;
    int m = (l+r)>>1;
    if( L<=m ) update(L,R,cmd,lson);
    else if( cmd == 'I' || cmd == 'C' ){
        PushDown(rt<<1);
        segT[rt<<1] = false,ud[rt<<1] = true;
    }
    if( m+1<=R ) update(L,R,cmd,rson);
    else if( cmd == 'I' || cmd == 'C' ){
        PushDown(rt<<1|1);
        segT[rt<<1|1] = false,ud[rt<<1|1] = true;
    }
    PushUp(rt);
}
void setIn(int l,int r,int rt){
    if( !segT[rt] ) return;
    if( ud[rt] ){
        for(int i=l ; i<=r ; i++) in[i] = true;
        return;
    }
    if( l == r ) return ;
    int m = (l+r)>>1;
    setIn(lson);
    setIn(rson);
}

int main(){
    // freopen("in","r",stdin);
    // freopen("out","w",stdout);

    build(0,maxn,1);

    char cmd,a,b;
    int L,R;
    while( scanf("%c %c%d,%d%c",&cmd,&a,&L,&R,&b) != EOF ){
        if( a=='(' ) L = L<<1|1;
        else L = L<<1;
        if( b==')' ) R = (R<<1) - 1;
        else R = R<<1;
        update(L,R,cmd,0,maxn,1);
        getchar();
    }
    if( ! segT[1] ) printf("empty set\n");
    else{
        memset(in,false,sizeof(in));
        bool first = true;
        setIn(0,maxn,1);
        for(int i=0 ; i<=maxn ; i++){
            if( in[i] ){
                int j = i ;
                for( ; in[j+1] ; j++);
                char a,b;
                if( i & 1 ) a = '(';
                else a = '[';
                if( j & 1 ) b = ')';
                else b = ']';
                if( !first ) printf(" ");
                printf("%c%d,%d%c",a,i>>1,(j+1)>>1,b );
                i = j+1 ;
                first = false;
            }
        }
        printf("\n");
    }

    return 0;
}

尝试写的用于生成测试数据的 python 代码:

import random
import sys

fileout = open("in","w")
sys.stdout = fileout

cmd = ['U','D','S','C','I']

for i in range(1,65535) :
	c = int(random.random() * 100) % 5
	a = int(random.random() * 100) % 2
	b = int(random.random() * 100) % 2
	l = random.randint(0,65535)
	r = random.randint(l,65535)
	while l>r :
		r = int(random.random() * 100)

	if a==0 :
		a = '('
	else :
		a = '['
	if b==0 :
		b = ')'
	else :
		b = ']'
	c = cmd[c]

	print c + ' ' + a + str(l) + ',' + str(r) + b

贴上几组测试数据:

(1)

D [27323,28582]
I (48593,49724]
C [52824,58649)
S (62504,63132]
D (6713,17378)
C [64279,64704)
U (43350,55633)
I (13250,61130]
C (8284,32422]
C [37148,52506]
S [36301,40476]
C [57254,58462)
S (6800,8020]
C (39395,42257]
U (40138,60510]
D (57476,59784)
U [40559,60039)
I (14862,39269]
D [17447,53082]
U (18103,35170)
C (54521,54592)
S [10509,37894]
U [46193,48617]
D (5915,12795]
I (31242,41783)

结果:(31242,37894]

(2)

D (20548,58380]
I [29921,50343]
C (55622,56388)
U (10663,55963)
S (13419,44485]
U (312,17641)
C (22888,46679)
I (146,34564)
S [52222,58635]
U (48414,52854]
D [63519,64154]
I (56730,58078)
S (35200,62027)
U [56629,59581]
U (34709,53176)
C (47617,50554)
C [59810,59879)
U [30945,35759]
S (63271,64382)
U (34039,58443)
S [34619,36867]
U [56291,64980)
U (28366,51780)
C [18035,62732]
S [31184,48714)
D [34641,64321]
I (35962,41647)
U (24485,65483)
D (54664,57957)
I (52186,61938)
C (5202,41608)
I [9726,37424]
U [6217,39511)
C (60703,64624)
D [60815,63894]
I [59317,63281]
U [40880,58971]

结果:[40880,58971] (60703,60815)

(3)

D (51901,59602]
C (27695,51572)
I (29957,43634)
D [64513,64737)
D (55877,58852)
D [50724,65161)
I (41470,64906)
I [21977,42189)
C [54859,58026)
C [7445,33368)
C [45127,61859)
I [49461,62419]
D [43476,47025)
S [25627,60097]
I (50585,60476]
I (36008,39441)
D [44098,48937)
D (5174,56696]
D (12119,45532]
C [33201,50399]
C (603,29859]
D [19415,53914]
U (35233,51370]
U [45301,45736)
U [60777,62008)
U [25292,51148)
S (50351,64164]
I (28419,49526]
S (56837,59700]
I (34427,50635]
C (28818,46140)
C (34941,61670]
C (54625,60209)
U (54769,57335]
S [8177,30820)
D (14943,28934]
I (43462,62257)

结果:(54769,57335]


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值