【POJ】2481 Cows
题目链接:http://poj.org/problem?id=2481
接着上文,那天下午接着刷了几道树状数组的题目,仍旧觉得树状数组使用已不是难题,困难点在于如何分析问题,转化为树状数组,有些题目刚刚拿到时,都不会觉得这能用树状数组解决?! 比如说这个题目……(其实也是个水题)
后来灰溜溜回去上线问了merlininice师父,他起先没说什么,看完题目就开始分析:
“ 如果我们按照每头牛的Ei值进行降序排序,接着按照重新排序后的牛开始数,找到第一头的时候先将他S1后面的都加1,找到第二头的时候,先看看他的S2的值是否为1:为1 的时候就说明第一头牛的区间有可能跨越他(还得额外判断E1==E2,S1==S2),然后再将S2后的也都加1……”
顿悟!
后来挨了一顿批。(虽然只是说了几句)
于是代码就跃然纸上了……
同时也更清晰地知道牛和菜的距离……
YY这么多后整理下该题的思路:

STEP1:对输入的数据按照结束点(Ei)进行排序。
STEP2:对排序后的点按照起始点(Si)先进行add(),接着统计从整段区间起始点到该点的和sum(Si),将和sum()-1 即可(因为事先进行了add()操作,目测先sum()再add()的话sum值即为其解)。
STEP3:输出即可。
为什么要排序?因为树状数组只能对前N项数组进行求和统计,那么当我们想要使用树状数组来解决题目的时候,就需要将问题转化为统计前N项的和的形式。对于这道题目,想要判断某个区间是否跨越另一个区间,我们如果按照Ei进行降序排序后,那么当我面遍历区间点的时候,如果发现add()之后sum()值大于1,说明有个区间的Sk在该区间起始点前(或者相等,针对这道题目,这种情况得特殊处理下),又因为区间按照Ei进行降序排列,那么之前的区间的Ei必然要大于(或者相等)该点,则该段区间必然被其他区间跨越了,至于有多少个跨越区间,只需要sum()-1即可。
如图举个实际例子:(我们已经将4个区间点按照Ei进行排序了)
遍历先从S1开始:add(s1,1), sum(s1)-1 = 0;
S2 :add(s2,1), sum(s2)-1 = 0;
S3 :add(s3,1), sum(s3)-1 = 2; (因为前面有s1和s2点值更新了s3点值,此刻s3的值为3)
S4 :add(s4,1), sum(s4)-1 = 2; (理由同上,同时,因为s3在s4之后,那么add(s3,1)不会更新到s4)
于是,答案就出来了……
下来后自己写,但是第一、二次都TLE了,后来参考了网上的做法,就AC了……
TLE的代码:(告诫后人,qsort()用一次就够了…)
while(~scanf("%d",&m), m){ memset(c,0,sizeof(c)); for(i=1; i<=m; ++i) { scanf("%d %d",&q[i].x,&q[i].y); q[i].x+=1; q[i].y+=1; q[i].id = i; } qsort(q+1,m,sizeof(q[0]),cmp); for(i=1; i<=m; ++i) { add(q[i].x,1); q[i].num =sum(q[i].x)-1; cout<<q[i].num<<endl; if(i>1 && q[i-1].y==q[i].y &&q[i-1].x==q[i].x ){ int k=i; while(k>1 && q[k].x==q[k-1].x && q[k].y==q[k-1].y){ q[i].num--; k--; } } } qsort(q+1,m,sizeof(q[0]),cmp1); cout<<q[1].num; for(i=2; i<=m; ++i) cout<<" "<<q[i].num; cout<<endl; }
AC的代码:
View Code
1 while(~scanf("%d",&m), m){ 2 memset(c,0,sizeof(c)); 3 n=0; 4 for(i=1; i<=m; ++i) { 5 scanf("%d %d",&q[i].x,&q[i].y); 6 q[i].x+=1; 7 q[i].y+=1; 8 q[i].id = i; 9 n=n>q[i].y ? n : q[i].y; 10 } 11 qsort(q+1,m,sizeof(q[0]),cmp); 12 13 for(i=1; i<=m; ++i) { 14 add(q[i].x,1); 15 ans[q[i].id] =sum(q[i].x)-1; 16 if(i>1 && q[i-1].y==q[i].y &&q[i-1].x==q[i].x ){ 17 int k=i; 18 while(k>1 && q[k].x==q[k-1].x && q[k].y==q[k-1].y){ 19 ans[q[i].id] --; 20 k--; 21 } 22 } 23 } 24 //qsort(q+1,m,sizeof(q[0]),cmp1); 25 26 cout<<ans[1]; 27 for(i=2; i<=m; ++i) cout<<" "<<ans[i]; 28 cout<<endl; 29 }
这道题目之后树状数组的概念就更清晰了,看来水水更健康也是没错的哈~~

浙公网安备 33010602011771号