【线段树II:区间修改+点查询】hdu 4031 Attack
2015-08-04 13:24
465 查看
【线段树II:区间修改+点查询】hdu 4031 Attack
题目链接:hdu 4031 Attack
题目大意
有位置1-n个防御塔,每次敌人会对一个区间进行攻击。防御塔有一个冷却时间t。问某个时间时,某个位置被成功攻击的次数(没有被防御)这是成都网络预选赛的题目。The 36th ACM/ICPC Asia Regional Chengdu Site —— Online Contest。
被攻击的次数 = 攻击的总次数 - 成功防守的次数 。
主要难点是怎样计算成功防守的次数,笔者from i to n 作标记 TLE了一次,AC的代码在最坏情况下O(n^2),即查询时所有的点都不同,可能后台数据弱一点就过了!相同的点总的查询时间之和是O(n),单个不同的点查询时间也是O(n),所以在计算成功防守次数时非常容易超时!!!!
说一下思路
攻击的总次数用线段树:区间修改+点查询,不难!成功防守的次数难想:如果简单的for i 1 to n 直接超时;虽然目前优化的结果能过,最差情况下 O(n),还是说一说:
(1)pos[x]表示第x个防御塔在上一次成功防守之后这一次开始防守的时刻;(2)def[x]表示第x个防御塔成功防守的次数,借助记忆数组pos[]的作用查询过程中不需要还原为0,不断累加即可(3)time记录总时间,seg[i]记录第i 时刻的attack区间
【In addition】这道题复习了一下线段树的区间修改、点查询,结果在成功保护的次数花了很多时间,好难想QAQ~
参考代码
/*====================================*\ |* 线段树 *| |* 区间修改、点查询 *| \*====================================*/ /*Author:Hacker_vision*/ #include<bits/stdc++.h> #define clr(k,v) memset(k,v,sizeof(k)) using namespace std; const int _max = 2e4 + 10; int n,m,t,x,y,pos[_max],def[_max]; char s[20]; struct segTree{ int lc,rc; int num;//区间[lc,rc]被攻击的次数(不考虑防守的) }segTree[_max<<2]; struct seg{ int l,r; }seg[_max];//存储输入区间的 void build(int root,int L,int R){//建立空线段树 segTree[root].lc = L; segTree[root].rc = R; segTree[root].num = 0; if(L == R) return ; int mid = (L + R) >> 1; build(root<<1,L,mid); build(root<<1|1,mid+1,R); } void update(int root,int L,int R){//区间修改 if(segTree[root].lc == L && segTree[root].rc == R){ segTree[root].num += 1; return ; } int mid = (segTree[root].lc + segTree[root].rc) >> 1; if(R <= mid) update(root<<1,L,R); else if(mid < L) update(root<<1|1,L,R); else{ update(root<<1,L,mid); update(root<<1|1,mid+1,R); } } int query(int root,int pos){//点查询 if(segTree[root].lc == pos && segTree[root].rc == pos) return segTree[root].num; int mid = (segTree[root].lc + segTree[root].rc) >> 1; if(pos <= mid) return segTree[root].num+query(root<<1,pos); else return segTree[root].num+query(root<<1|1,pos); } int main(){ #ifndef ONLINE_JUDGE freopen("input.txt","r",stdin); #endif // ONLINE_JUDGE int T;cin>>T;int cnt = 1; while(T--){ scanf("%d%d%d",&n,&m,&t); build(1,1,n); int time = 0; bool ok = true; clr(pos,0);//pos[i]表示第i个堡垒上一次成功保护之后下次开始保护的位置 clr(def,0);//def[i]记录堡垒i成功保护(defend)的次数,默认为0 for(int i = 0; i < m; ++ i){ scanf("%s",s); if(s[0]=='A'){ scanf("%d%d",&x,&y); update(1,x,y); seg[time].l = x; seg[time].r = y; time ++;//time既作总时间,也可作区间下标 } else{ scanf("%d",&x); if(ok) printf("Case %d:\n",cnt++);ok=false; for(int j = pos[x];j < time; ){ if(seg[j].l <= x && x <= seg[j].r){ def[x]++;//第x个堡垒成功保护次数增加一次 j = j + t; pos[x]=j;//记录下次查询该节点的起始位置 } else j ++ ; //继续向下查询 } printf("%d\n", query(1,x)-def[x]); } } } return 0; }
加粗
Ctrl + B
斜体
Ctrl + I
引用
Ctrl + Q
插入链接
Ctrl + L
插入代码
Ctrl + K
插入图片
Ctrl + G
提升标题
Ctrl + H
有序列表
Ctrl + O
无序列表
Ctrl + U
横线
Ctrl + R
撤销
Ctrl + Z
重做
Ctrl + Y
相关文章推荐
- 线段树题集
- hdu1754
- HDU1394
- 敌兵布阵 (1)
- I Hate It (1)
- LCIS (2)
- A Simple Problem with Integers (2)
- Mayor's posters (3)
- Buy Tickets (3)
- 线段树
- UVA - 12532 Interval Product
- POJ 3264 Balanced Lineup
- hdu 1542 求矩形并的面积
- 关于数据结构之线段树
- poj 3225 关于集合运算
- poj 2352
- hdu1166敌兵布阵(线段树点修改)
- POJ 2352 Stars 线段树 pascal
- hdu 1698 Just A Hook 线段树的一道题
- HDU 1754 I Hate It