poj 3667 线段树,区间合并

来源:互联网 发布:奥一网 网络问政 编辑:程序博客网 时间:2024/05/21 11:18

题意:给N 个空房间,有M次操作,1是 去连续x 房间为空的第一个房间号 && 房间号最小; 2:将[x ,x+y-1] 房间清空;

思路: 用mark ==0 表示当前这个区间状态未定,mark= 1 表示要将此区间的子区间全部清空(房间全部可使用) mark=2 表示 此区间的子区间 的房子全部入住满;

ms 为此区间最大连续为空的房间数; ls 为区间从最左端开始连续为空的房间数,rs 为区间从最右端开始连续为空的房间数;

len 为区间的总房间数; pos 记录ms 的起始房间号;

第二遍写时候犯很多逗比错误: build—tree() 时候没有管mark 的初始;

node(int ms=0,int rs=0,int ls=0) 懒省事只写了3 个变量,误以为这样就可以只给这三个变量赋值,其他不变! node() 函数是会把里面的东西全部重新替换的!没有写的变量系统随机生成数字!C++ 语法没认真学的后果;

#include<stdio.h>#include<string.h>#include<math.h>#include<string>#include<iostream>#include<algorithm>#include<vector>#include<queue>#include<list>#include<map>#include<set>using namespace std;const int N = 50010;int n, m;struct node{    int ms,ls,rs;    int pos,len,mark;    node(int ms=0,int ls=0,int rs=0,int len=0,int pos=0,int mark=0):        ms(ms),ls(ls),rs(rs),len(len),pos(pos),mark(mark){}};node tree[N * 4];void tree_build(int st, int ed, int i){    int L = ed - st + 1;    tree[i]=node(L, L, L, L, st, 0);    if(st == ed) return ;    int mid = (st + ed) >> 1;    tree_build(st, mid, i * 2);    tree_build(mid + 1, ed, i * 2 + 1);}void tree_down_data(int st, int ed, int i){    if(tree[i].mark == 0 || st == ed) return ;    int mid = (st + ed) >> 1;    int fi = i * 2, se = i * 2 + 1;    if(tree[i].mark == 1){        int L = tree[fi].len;        tree[fi] = node(L, L, L, L, st, 1);        L = tree[se].len;        tree[se] = node(L ,L, L, L, mid + 1, 1);    }    else if(tree[i].mark == 2){        int L = tree[fi].len;        tree[fi] = node(0, 0, 0, L, st, 2);        L = tree[se].len;        tree[se] = node(0, 0, 0, L, mid + 1, 2);    }    tree[i].mark = 0;}int tree_query(int len, int st, int ed, int i){//    printf("Q:len=%d, st = %d ,ed= %d ,i = %d\n",len,st,ed,i);    tree_down_data(st, ed, i);    if(tree[i].ms < len) return 0;    if(st == ed){        return tree[i].pos;    }    int mid = (st + ed) >> 1;    if(tree[i * 2].ms >= len)         return tree_query(len, st, mid, i * 2);    else if(tree[i * 2].rs + tree[i * 2 + 1].ls >= len)         return mid - tree[i * 2].rs + 1;    else return tree_query(len, mid + 1, ed , i * 2 + 1);}void tree_up_data(int st, int ed, int i){    int mid = (st + ed) >> 1;    int fi = i * 2, se = i * 2 + 1;    tree[i].ls = tree[fi].ls;      if(tree[fi].ls == tree[fi].len)  // 当左儿子全部为空时        tree[i].ls += tree[se].ls;  // 加上右儿子的最大连续左区    tree[i].rs = tree[se].rs;    if(tree[se].rs == tree[se].len)        tree[i].rs += tree[fi].rs;    tree[i].ms = max(tree[fi].rs + tree[se].ls , max(tree[fi].ms, tree[se].ms) );      // 当前区间的连续最大可以来自于左儿子最大,右儿子最大,或者是左儿子的右端+右儿子的左端;    if(tree[i].ms == tree[fi].ms) tree[i].pos = tree[fi].pos;         // pos 维护是连续为空的房间数最大 && 最靠近左端的起点;              //要考虑如果tree[fi].ms ==tree[fi].rs + tree[se].ls ||              //tree[fi].ms == tree[se].ms 优先选取 tree[fi].pos;    else if (tree[i].ms == tree[fi].rs + tree[se].ls)           tree[i].pos = (st + ed) >> 1 - tree[fi].rs + 1; // 同理;    else tree[i].pos = tree[se].pos;}void tree_add(int op, int x, int y, int st, int ed, int i){    tree_down_data(st, ed, i);    if(x > ed || y < st) return ;    if(x <= st && y >= ed) {       if(op == 1){   //房间全部标记为可以入住;            int L = tree[i].len ;            tree[i] = node(L ,L, L, L, st, op);       }       else{            int L = tree[i].len;            tree[i] = node(0, 0, 0, L, st, op);       }       return ;    }    int mid = (st + ed) >> 1;    tree_add(op, x, y, st, mid, i * 2);    tree_add(op, x, y, mid + 1, ed, i * 2 + 1);    tree_up_data(st, ed, i);}void debug(int st, int ed, int i){    printf("st=%d ed= %d i= %d:\n",st, ed, i);    printf("ms=%d,ls=%d,rs=%d,len=%d,mark=%d\n",tree[i].ms,tree[i].ls,tree[i].rs,tree[i].len,tree[i].mark);    if(st == ed) return ;    int mid = (st + ed) >> 1;    debug(st, mid ,i * 2);    debug(mid + 1, ed, i * 2 + 1);}int main(){//freopen("in.in","r",stdin);    while(~scanf("%d%d",&n,&m)){        tree_build(1, n, 1);//        debug(1, n, 1);        int op, x, y;        while(m--){            scanf("%d",&op);            if(op == 1){                scanf("%d", &x);                int ans = tree_query(x, 1, n, 1);                cout << ans << endl;                if(ans == 0)                    continue;  // 注意ans = 0 跳过!                tree_add(2, ans, ans + x -1, 1, n, 1);//                debug(1, n, 1);            }            else {                scanf("%d%d",&x,&y);                tree_add(1, x, x + y - 1 , 1, n, 1);            }        }    }return 0;}

一星期前的写法:

#include<stdio.h>#include<string.h>#include<math.h>#include<string>#include<iostream>#include<algorithm>#include<vector>#include<queue>#include<list>#include<map>#include<set>using namespace std;const int maxn=50100;struct node{   int ls,rs,ms,pos,mark;   node(int ls=0,int rs=0,int ms=0,int pos=0,int mark=0):ls(ls),rs(rs),ms(ms),pos(pos),mark(mark){}}tree[4*maxn];void build_tree(int st,int ed,int i){   tree[i]=node(ed-st+1,ed-st+1,ed-st+1,st,0);   if(st==ed) return ;   int mid=(st+ed)>>1;   build_tree(st,mid,i*2);   build_tree(mid+1,ed,i*2+1);}bool is_all_clear(int st,int ed,int i){  if(tree[i].ls==ed-st+1) return 1;  else return 0;}void update(int st,int ed,int i){    if(tree[i].mark==0) return;    int mid=(st+ed)/2;    if(tree[i].mark==1){        tree[i*2]=node(mid-st+1,mid-st+1,mid-st+1,st,1);        tree[i*2+1]=node(ed-mid,ed-mid,ed-mid,mid+1,1);    }    else {       tree[i*2]=node(0,0,0,st,2);       tree[i*2+1]=node(0,0,0,mid+1,2);    }    tree[i].mark=0;}int query(int len,int st,int ed,int i){    update(st,ed,i);    if(tree[i].ms<len) return 0;    if(tree[i].ms==len) return tree[i].pos;    int mid=(st+ed)/2;    if(tree[i*2].ms>=len)        return query(len,st,mid,i*2);    if(tree[i*2].rs+tree[i*2+1].ls>=len)        return mid-tree[i*2].rs+1;    return query(len,mid+1,ed,i*2+1);}void get_max(node &pre,node &p1,node &p2,int mid){   int len=p1.rs+p2.ls;   if(p1.ms>=len && p1.ms>=p2.ms){       pre.ms=p1.ms;       pre.pos=p1.pos;       return;   }   else if(len>p1.ms && len>=p2.ms){        pre.ms=len;        pre.pos=mid-p1.rs+1;        return ;   }   else if(p2.ms>p1.ms && p2.ms>len){       pre.ms=p2.ms;       pre.pos=p2.pos;       return ;   }}void change(int x,int y,int st,int ed,int i,bool fg){    if(x>ed || y<st) return ;    if(x<=st && y>=ed) {        if(fg)            tree[i]=node(0,0,0,st,2);        else            tree[i]=node(ed-st+1,ed-st+1,ed-st+1,st,1);        return;    }    update(st,ed,i);    int mid=(st+ed)/2;    change(x,y,st,mid,i*2,fg);    change(x,y,mid+1,ed,i*2+1,fg);    tree[i].ls=tree[i*2].ls;    if(is_all_clear(st,mid,i*2)) tree[i].ls+=tree[i*2+1].ls;    tree[i].rs=tree[i*2+1].rs;    if(is_all_clear(mid+1,ed,i*2+1)) tree[i].rs+=tree[i*2].rs;    get_max(tree[i],tree[i*2],tree[i*2+1],mid);}int main(){//     freopen("in.in","r",stdin);     int n,m,choice,st,len;     while(~scanf("%d%d",&n,&m)){        build_tree(1,n,1);        while(m--){            scanf("%d",&choice);            if(choice==1){                scanf("%d",&len);                int ans=query(len,1,n,1);                cout<<ans<<endl;                if(ans)                    change(ans,ans+len-1,1,n,1,1);            }            else{                scanf("%d%d",&st,&len);                change(st,st+len-1,1,n,1,0);            }        }     }     return 0;}


0 0
原创粉丝点击