hdu1166线段树
****************************************************第四个博客*****************************************************
一直在进步
相信自己
就算最后不成功也会有进步
相信自己
就算最后不成功也会有进步
****************************************************第四个博客*****************************************************
排兵布阵
题目地址在这:http://acm.hdu.edu.cn/showproblem.php?pid=1166
Problem Description
C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了。A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视 这些工兵营地的活动情况。由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减 少若干人手,但这些都逃不过C国的监视。
中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少人,例如Derek问:“Tidy,马上汇报第3个营地到第10个营地共有多少人!”Tidy就要马上开始计算这一段的总人数并汇报。但敌兵营地的人数经常变动,而Derek每次询问的段都不一样,所以Tidy不得不每次都一个一个营地的去数,很快就精疲力尽了,Derek对Tidy的计算速度越来越不满:"你个死肥仔,算得这么慢,我炒你鱿鱼!”Tidy想:“你自己来算算看,这可真是一项累人的工作!我恨不得你炒我鱿鱼呢!”无奈之下,Tidy只好打电话向计算机专家Windbreaker求救,Windbreaker说:“死肥仔,叫你平时做多点acm题和看多点算法书,现在尝到苦果了吧!”Tidy说:"我知错了。。。"但Windbreaker已经挂掉电话了。Tidy很苦恼,这么算他真的会崩溃的,聪明的读者,你能写个程序帮他完成这项工作吗?不过如果你的程序效率不够高的话,Tidy还是会受到Derek的责骂的.
Input
第一行一个整数T,表示有T组数据。
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地
里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现; 每组数据最多有40000条命令
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地
里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现; 每组数据最多有40000条命令
Output
对第i组数据,首先输出“Case i:”和回车,
对于每个Query询问,输出一个整数并回车,表示询问的段中的总人数,这个数保持在int以内。
Sample Input
1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End
Sample Output
Case 1:
6
33
59
6
33
59
这题如果暴力的话,毫无疑问会爆,所以我采用了线段树,主要分为三步,最首先建树:
1 void build(int left,int right,int root) 2 { 3 a[root].l=left; 4 a[root].r=right; 5 if(left==right) 6 { 7 a[root].num=fen[left]; 8 return; 9 } 10 int mid=(left+right)/2; 11 build(left,mid,root*2); 12 build(mid+1,right,root*2+1); 13 a[root].num=(a[root*2].num+a[root*2+1].num); 14 return; 15 }
按照题目要求,需要更新数的num,在更新每个叶子节点(第i个营地)的同时更新它的祖先节点:
1 void update(int p,int q,int root) 2 { 3 if(a[root].l==a[root].r&&a[root].l==p) 4 { 5 a[root].num+=q; 6 return; 7 } 8 if(p<=a[root*2].r) 9 { 10 update(p,q,root*2); 11 } 12 else 13 { 14 update(p,q,root*2+1); 15 } 16 a[root].num=(a[root*2].num+a[root*2+1].num); 17 return; 18 }
最后需要一个询问的函数,运用查找的方法确定询问的i到j的位置:
1 int query(int left,int right,int root) 2 { 3 if(a[root].l==left&&a[root].r==right) 4 { 5 return a[root].num; 6 } 7 if(right<=a[root*2].r) 8 { 9 return query(left,right,root*2); 10 } 11 else if(left>=a[root*2+1].l) 12 { 13 return query(left,right,root*2+1); 14 } 15 else{ 16 int mid=(a[root].l+a[root].r)/2; 17 return query(left,mid,root*2)+query(mid+1,right,root*2+1); 18 } 19 }
ac代码如下:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #define N 200005 5 using namespace std; 6 7 struct mem{ 8 int l, r, num; 9 }a[N*4]; 10 11 int fen[N]; 12 void build(int left,int right,int root) 13 { 14 a[root].l=left; 15 a[root].r=right; 16 if(left==right) 17 { 18 a[root].num=fen[left]; 19 return; 20 } 21 int mid=(left+right)/2; 22 build(left,mid,root*2); 23 build(mid+1,right,root*2+1); 24 a[root].num=(a[root*2].num+a[root*2+1].num); 25 return; 26 } 27 28 void update(int p,int q,int root) 29 { 30 if(a[root].l==a[root].r&&a[root].l==p) 31 { 32 a[root].num+=q; 33 return; 34 } 35 if(p<=a[root*2].r) 36 { 37 update(p,q,root*2); 38 } 39 else 40 { 41 update(p,q,root*2+1); 42 } 43 a[root].num=(a[root*2].num+a[root*2+1].num); 44 return; 45 } 46 int query(int left,int right,int root) 47 { 48 if(a[root].l==left&&a[root].r==right) 49 { 50 return a[root].num; 51 } 52 if(right<=a[root*2].r) 53 { 54 return query(left,right,root*2); 55 } 56 else if(left>=a[root*2+1].l) 57 { 58 return query(left,right,root*2+1); 59 } 60 else{ 61 int mid=(a[root].l+a[root].r)/2; 62 return query(left,mid,root*2)+query(mid+1,right,root*2+1); 63 } 64 } 65 int main() 66 { 67 int i, j, n, m, x, y; 68 char c[10]; 69 scanf("%d",&m); 70 int mm=m; 71 while(mm--) 72 { 73 printf("Case %d:\n",m-mm); 74 scanf("%d",&n); 75 for(i=1;i<=n;i++) 76 scanf("%d",&fen[i]); 77 getchar(); 78 build(1,n,1); 79 80 while(1) 81 { 82 scanf("%s",&c); 83 if(c[0]=='E') 84 break; 85 scanf("%d%d",&x,&y); 86 getchar(); 87 if(c[0]=='A') 88 { 89 update(x,y,1); 90 } 91 if(c[0]=='S') 92 { 93 update(x,-y,1); 94 } 95 if(c[0]=='Q') 96 { 97 printf("%d\n",query(x,y,1)); 98 } 99 } 100 101 } 102 return 0; 103 }
posted on 2016-04-21 14:59 haoxihuanni 阅读(133) 评论(0) 收藏 举报
浙公网安备 33010602011771号