HDU-4553 约会安排(线段树维护连续区间)
http://acm.hdu.edu.cn/showproblem.php?pid=4553
Problem Description
小明虽为屌丝级码农,但非常活跃,女神们常常在小明网上的大段发言后热情回复“呵呵”,所以,小明的最爱就是和女神们约会。与此同时,也有很多基友找他开黑,由于数量实在过于巨大,怎么安排时间便成了小明的一大心事。
我们已知小明一共有T的空闲时间,期间会有很多女神或者基友来找小明。
作为一个操作系统曾经怒考71分的大神,小明想到了一个算法,即“首次适应算法”,根据操作系统课本的描述,就是找一段最靠前的符合要求的连续空间分配给每个请求,由此小明做出了一个决定:
当一个基友来找小明时,小明就根据“首次适应算法”来找一段空闲的时间来和基友约好,如果找到,就说“X,let’s fly”(此处,X为开始时间),否则就说“fly with yourself”;
当女神来找小明时,先使用一次“首次适应算法”,如果没有找到,小明就冒着木叽叽的风险无视所有屌丝基友的约定,再次使用“无视基友首次适应算法”,两次只要有一次找到,就说“X,don’t put my gezi”(此处,X为开始时间),否则就说“wait for me”
当然,我们知道小明不是一个节操负无穷的人,如果和女神约会完,还有剩余时间,他还是会和原来约好的基友去dota的。(举个例子:小西(屌丝)和小明约好在1~5这个时间单位段内打dota,这时候,女神来和小明预约长度为3的时间段,那么最终就是1~3小明去和女神约会,搞定后在4~5和小西打dota)
小明偶尔也会想要学习新知识,此时小明就会把某一个时间区间的所有已经预定的时间全部清空用来学习并且怒吼“I am the hope of chinese chengxuyuan!!”,不过小明一般都是三分钟热度,再有人来预定的话,小明就会按耐不住寂寞把学习新知识的时间分配出去。
Input
输入第一行为CASE,表示有CASE组测试数据;
每组数据以两个整数T,N开始,T代表总共的时间,N表示预约请求的个数;
接着的N行,每行表示一个女神或者基友的预约,“NS QT”代表一个女神来找小明约一段长为QT的时间,“DS QT”则代表一个屌丝的长为QT的请求,当然也有可能是小明想学知识了,“STUDY!! L R”代表清空L~R区间内的所有请求。
[Technical Specification]
1. 1 <= CASE <= 30
2. 1 <= T, N <= 100000
3. 1 <= QT <= 110000
4. 1 <= L <= R <=T
Output
对于每一个case,第一行先输出“Case C:”代表是第几个case,然后N行,每行对应一个请求的结果(参照描述)。
输出样本(可复制此处):
“X,let's fly”,”fly with yourself”,”X,don't put my gezi”,”wait for me”,”I am the hope of chinese chengxuyuan!!”
Sample Input
1 5 6 DS 3 NS 2 NS 4 STUDY!! 1 5 DS 4 NS 2
Sample Output
Case 1: 1,let's fly 4,don't put my gezi wait for me I am the hope of chinese chengxuyuan!! 1,let's fly 1,don't put my gezi
题意:
也就是一个优先级问题,学习优先级最高,其次约女神,约屌丝最低
思路:
若有基友约,直接判断A是否还有位置,有就更新A区间。
若有女神约,则先判断A是否有位置,有就同时更新区间A和B,否则再判断B是否有位置(忽视约屌丝),若有还是同时更新区间A和B。
这里的标记我是直接用 最长连续区间的值表示,因为答应基友或者女神,那么有一段的最长连续区间肯定为0。
如果要学习 那么这一段的最长连续区间恢复成这一段的长度。
反思:
刚开始一直wa,不知道为啥,改BUG改了几个小时,绝望时看了oj平台上的comment,
看到了这两个评论:
Re:题目里把英文引号写成了中文,注意!!!!
Re:注意题目中的单引号,他给的是中文,记得改成英文!!!!不然会WA到哭。。。。。。。。。
wa到哭了,都怪自己没注意,复制的题目中的话,而不是样例输出中的话,哎,长记性了,以后代码的输出要在给的标准输出里面复制,不要再在文章里面复制了。
代码如下:
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <string> 5 #include <math.h> 6 #include <algorithm> 7 #include <vector> 8 #include <queue> 9 #include <set> 10 #include <stack> 11 #include <map> 12 #include <math.h> 13 const int INF=0x3f3f3f3f; 14 typedef long long LL; 15 const int mod=1e9+7; 16 //const double PI=acos(-1); 17 const int maxn=1e5+10; 18 using namespace std; 19 //ios::sync_with_stdio(false); 20 // cin.tie(NULL); 21 22 struct SegTree_node 23 { 24 int l; 25 int r; 26 int ls;//ls 包含左端点的最长连续区间 27 int rs;//rs 包含右端点的最长连续区间 28 int ms;//ms 最长连续区间 29 }SegTree[2][maxn<<2];//SegTree[0]代表有人约的时间 ,SegTree[1]代表女神约的时间 30 31 void Build(int l,int r,int rt) 32 { 33 SegTree[0][rt].l=SegTree[1][rt].l=l; 34 SegTree[0][rt].r=SegTree[1][rt].r=r; 35 SegTree[0][rt].ls=SegTree[0][rt].rs=SegTree[0][rt].ms=r-l+1; 36 SegTree[1][rt].ls=SegTree[1][rt].rs=SegTree[1][rt].ms=r-l+1; 37 if(l==r) 38 return ; 39 int mid=(l+r)>>1; 40 Build(l,mid,rt<<1); 41 Build(mid+1,r,rt<<1|1); 42 } 43 44 void PushUp(int rt) 45 { 46 int l=SegTree[0][rt].l; 47 int r=SegTree[0][rt].r; 48 SegTree[0][rt].ls=SegTree[0][rt<<1].ls;//左子树的左连续区间肯定是父亲节点左连续区间的一部分 49 SegTree[0][rt].rs=SegTree[0][rt<<1|1].rs;//同理 50 //父亲节点的最长连续区间要么是 左子树的最长连续区间 要么 右子树的最长连续区间 要么 左子树右连续+右子树左连续 51 SegTree[0][rt].ms=max(SegTree[0][rt<<1].rs+SegTree[0][rt<<1|1].ls,max(SegTree[0][rt<<1].ms,SegTree[0][rt<<1|1].ms)); 52 //如果左子树的左连续长度为整个左子树的长度,那么父亲节点的左连续区间得加上 右子树的左连续区间 53 if(SegTree[0][rt<<1].ls==SegTree[0][rt<<1].r-SegTree[0][rt<<1].l+1) 54 SegTree[0][rt].ls+=SegTree[0][rt<<1|1].ls; 55 if(SegTree[0][rt<<1|1].rs==SegTree[0][rt<<1|1].r-SegTree[0][rt<<1|1].l+1)//同理 56 SegTree[0][rt].rs+=SegTree[0][rt<<1].rs; 57 58 SegTree[1][rt].ls=SegTree[1][rt<<1].ls; 59 SegTree[1][rt].rs=SegTree[1][rt<<1|1].rs; 60 SegTree[1][rt].ms=max(SegTree[1][rt<<1].rs+SegTree[1][rt<<1|1].ls,max(SegTree[1][rt<<1].ms,SegTree[1][rt<<1|1].ms)); 61 if(SegTree[1][rt<<1].ls==SegTree[1][rt<<1].r-SegTree[1][rt<<1].l+1) 62 SegTree[1][rt].ls+=SegTree[1][rt<<1|1].ls; 63 if(SegTree[1][rt<<1|1].rs==SegTree[1][rt<<1|1].r-SegTree[1][rt<<1|1].l+1) 64 SegTree[1][rt].rs+=SegTree[1][rt<<1].rs; 65 } 66 67 void PushDown(int rt)//下推标记 68 { 69 int l=SegTree[0][rt].l; 70 int r=SegTree[0][rt].r; 71 int mid=(l+r)>>1; 72 if(SegTree[0][rt].ms==r-l+1)//可能是学习操作造成的要下推 73 { 74 SegTree[0][rt<<1].ls=SegTree[0][rt<<1].rs=SegTree[0][rt<<1].ms=mid-l+1; 75 SegTree[0][rt<<1|1].ls=SegTree[0][rt<<1|1].rs=SegTree[0][rt<<1|1].ms=r-mid; 76 } 77 else if(SegTree[0][rt].ms==0)//由约人操作造成 78 { 79 SegTree[0][rt<<1].ls=SegTree[0][rt<<1].rs=SegTree[0][rt<<1].ms=0; 80 SegTree[0][rt<<1|1].ls=SegTree[0][rt<<1|1].rs=SegTree[0][rt<<1|1].ms=0; 81 } 82 83 if(SegTree[1][rt].ms==r-l+1) 84 { 85 SegTree[1][rt<<1].ls=SegTree[1][rt<<1].rs=SegTree[1][rt<<1].ms=mid-l+1; 86 SegTree[1][rt<<1|1].ls=SegTree[1][rt<<1|1].rs=SegTree[1][rt<<1|1].ms=r-mid; 87 } 88 else if(SegTree[1][rt].ms==0) 89 { 90 SegTree[1][rt<<1].ls=SegTree[1][rt<<1].rs=SegTree[1][rt<<1].ms=0; 91 SegTree[1][rt<<1|1].ls=SegTree[1][rt<<1|1].rs=SegTree[1][rt<<1|1].ms=0; 92 } 93 } 94 95 void Update(int L,int R,int flag,int rt) 96 { 97 int l=SegTree[0][rt].l; 98 int r=SegTree[0][rt].r; 99 if(L<=l&&R>=r) 100 { 101 if(flag==0)//约基友 102 { 103 SegTree[0][rt].ls=SegTree[0][rt].rs=SegTree[0][rt].ms=0; 104 } 105 else if(flag==1)//约女神,要同时修改两个区间 106 { 107 SegTree[0][rt].ls=SegTree[0][rt].rs=SegTree[0][rt].ms=0; 108 SegTree[1][rt].ls=SegTree[1][rt].rs=SegTree[1][rt].ms=0; 109 } 110 else//学习,要同时修改两个区间 111 { 112 SegTree[0][rt].ls=SegTree[0][rt].rs=SegTree[0][rt].ms=r-l+1; 113 SegTree[1][rt].ls=SegTree[1][rt].rs=SegTree[1][rt].ms=r-l+1; 114 } 115 return ; 116 } 117 PushDown(rt); 118 int mid=(l+r)>>1; 119 if(L<=mid) 120 Update(L,R,flag,rt<<1); 121 if(R>mid) 122 Update(L,R,flag,rt<<1|1); 123 PushUp(rt); 124 } 125 126 int Query(int flag,int QT,int rt) 127 { 128 int l=SegTree[flag][rt].l; 129 int r=SegTree[flag][rt].r; 130 if(l==r) 131 return l; 132 PushDown(rt); 133 int mid=(l+r)>>1; 134 if(SegTree[flag][rt<<1].ms>=QT) 135 return Query(flag,QT,rt<<1); 136 else if(SegTree[flag][rt<<1].rs+SegTree[flag][rt<<1|1].ls>=QT) 137 return mid-SegTree[flag][rt<<1].rs+1; 138 else 139 return Query(flag,QT,rt<<1|1); 140 } 141 142 int main() 143 { 144 //freopen("sample.txt","r",stdin); 145 int CASE; 146 scanf("%d",&CASE); 147 for(int k=1;k<=CASE;k++) 148 { 149 int T,N; 150 scanf("%d %d",&T,&N); 151 printf("Case %d:\n",k); 152 Build(1,T,1); 153 char str[10]; 154 while(N--) 155 { 156 scanf("%s",str); 157 if(str[0]=='D') 158 { 159 int QT; 160 scanf("%d",&QT); 161 if(SegTree[0][1].ms>=QT)//看整个区间内的最长连续区间是否满足QT 162 { 163 int t=Query(0,QT,1); 164 printf("%d,let's fly\n",t); 165 Update(t,t+QT-1,0,1); 166 } 167 else 168 printf("fly with yourself\n"); 169 } 170 else if(str[0]=='N') 171 { 172 int QT; 173 scanf("%d",&QT); 174 if(SegTree[0][1].ms>=QT) 175 { 176 int t=Query(0,QT,1); 177 printf("%d,don't put my gezi\n",t); 178 Update(t,t+QT-1,1,1); 179 } 180 else if(SegTree[1][1].ms>=QT) 181 { 182 int t=Query(1,QT,1); 183 printf("%d,don't put my gezi\n",t); 184 Update(t,t+QT-1,1,1); 185 } 186 else 187 printf("wait for me\n"); 188 } 189 else if(str[0]=='S') 190 { 191 int L,R; 192 scanf("%d %d",&L,&R); 193 Update(L,R,2,1); 194 printf("I am the hope of chinese chengxuyuan!!\n"); 195 } 196 } 197 } 198 return 0; 199 }
贴出参考的博客:
https://blog.csdn.net/dsaghjkye/article/details/81069500
https://www.xuebuyuan.com/3225923.html
另一种思路,单个线段树加屌丝、女神标记的解法:
https://blog.csdn.net/qq_36782366/article/details/75206287