POJ 2528 Mayor's posters

来源:互联网 发布:菲律宾进出口数据 编辑:程序博客网 时间:2024/06/05 16:30

题目大意:

        城中的市民已经无法忍受市长候选人到处乱贴竞选海报了,因此地方议会决定建立一座竞选墙以供竞选者贴海报,并制定以下规则:

                每位竞选人只能贴一张海报;

                海报的高度和墙的高度一致,宽度是一个正整数;

                墙的总长为10,000,000,以1为单位;

                海报必须占据连续的一段,不能分为多张;

        海报将按顺序贴,可以覆盖别人已经占据的位置,大多数海报的宽度都是不一样的,因此大家都很期待在竞选前一天有哪些海报是可见的(完整或者部分被覆盖(没有完全被覆盖));

        现有多个测例(测例数为c,题中给出),每个测例中都会告诉总共有多少个(n个,n ≤ 10,000)候选人(即会贴出多少张海报),接着按顺序给出每张海报的左边和右边界限在墙上的坐标,试求出最后总共有多少张海报可见。

题目链接

注释代码:

/*            * Problem ID : POJ 2528 Mayor's posters * Author     : Lirx.t.Una            * Language   : G++       * Run Time   : 63 ms            * Run Memory : 33864 KB           */  #pragmaG++ optimize("O2")#include <string.h>#include <stdlib.h>#include <stdio.h>#defineTRUE1#defineFALSE0//可看成是颜色覆盖问题,NONE表示无色#defineNONE0/* *==由于题目要求空间不得大于65536KB, *==但是竞选墙的宽度为10,000,000,过大, *==而实际海报数有很少,只要10,000张,因此 *==最多只会得到200,000中不同的坐标,也就是说 *==10,000,000个坐标中最多只会用到200,000个, *==因此可以将得到的这200,000个坐标(去掉其中 *==重复的),映射到1-200,000这个新的坐标系中 *==然后对该新的坐标系构建线段树,这样就不会 *==超出空间要求了*///maximum number of posters,海报的最大数量,10,000 + 1#defineMAXPOSTERN10001//maxumum transformed coordinate,最大的变换坐标#defineMAXXCORD20001//线段树的最大范围//65536 = 1 << ( 1 + ceil( log2(20000) ) )#defineMAXSEGSIZE65536//最大原坐标//用于将原坐标映射到压缩坐标#defineMAXCORD10000001typedefcharBOOL;typedefstruct {intlft;intrht;intcol;//color,段的颜色} Seg;intlft[MAXPOSTERN];//lft[i]表示第i张海报的左界坐标intrht[MAXPOSTERN];//rht[i]表示第i张海报的右界坐标BOOLbcl[MAXPOSTERN];//be calculate,bcl[i]表示                //第i张海报所代表的颜色是否被计算过intcord[MAXXCORD];//coordinate,记录200,000个坐标值intxcod[MAXCORD];//transformed coordinate,变换压缩坐标                //xcod[ 老坐标 ] = 变换后的新坐标Segs[MAXSEGSIZE];intans;//最后又多少张海报可见voidbuild( int r, int lft, int rht ) {s[r].lft = lft;s[r].rht = rht;s[r].col = NONE;if ( lft == rht )return ;intlc;intmid;lc= r + r;mid = ( lft + rht ) >> 1;build( lc, lft, mid );build( lc + 1, mid + 1, rht );}voidpaint( int r, int lft, int rht, int col ) {//给线段树上色,就是update      //给以r为根的线段树的lft-rht区间内上col这种颜色if ( lft == s[r].lft && rht == s[r].rht ) {    //若上色区间刚好等于当前结点所表示的区间,则直接对该区间上色s[r].col = col;return ;}intlc, rc;//左右子树intmid;//当前结点所表示的段的中间位置lc= r + r;rc= lc + 1;mid = s[lc].rht;if ( s[r].col ) {//若当前结点已经上过色了//但是目前又不能完全覆盖该段,只能部分覆盖该段//因此只能先将当前结点的颜色传递给下面的段//然后再在下面的段继续上色//同时也要将当前段重新刷新为无色s[lc].col = s[r].col;s[rc].col = s[r].col;s[r].col  = NONE;}if ( rht <= mid ) {//若上色区间在左半段paint( lc, lft, rht, col );return ;}if ( lft > mid ) {//上色区间在右半段paint( rc, lft, rht, col );return ;}//上色区间跨越中点paint( lc, lft, mid, col );paint( rc, mid + 1, rht, col );}voidcal(int r) {//calculate,计算有多少海报可见intcol;col= s[r].col;//记录了根结点的颜色if (col) {//若根结点有色,那就代表根结点//所代表的段都被覆盖了这种颜色,那么//下面的段就不用再检查了if ( !bcl[col] ) {//若该颜色没被计算过//那么就记录一下ans++;bcl[col] = TRUE;}return ;}intlc;//若当前结点无色,说明有可能是它的子//段被上色了,然后继续检查其子段的颜色即可lc = r + r;cal(lc);cal( lc + 1 );}intfcmp(const void *a, const void *b) {return *(int *)a - *(int *)b;}intmain() {intc;intn;inti, j;scanf("%d", &c);while ( c-- ) {scanf("%d", &n);memset(bcl + 1, FALSE, n * sizeof(BOOL));for ( i = 1, j = 1; i <= n; i++, j++ ) {scanf("%d%d", lft + i, rht + i);//将所有出现的坐标都记录在一个数组中cord[j++] = lft[i];cord[j]  = rht[i];}//对该数组排序后挑出互不相同的坐标qsort(cord + 1, n + n, sizeof(int), &fcmp);for ( j = 1, i = 1; j <= n + n; j++, i++ ) {cord[i]= cord[j];xcod[ cord[i] ] = i;//将这些互不相同的坐标映射到       //压缩后的坐标系中while ( j < n + n && cord[j] == cord[j + 1] )//排除相同的坐标j++;}build( 1, 1, i - 1 );for ( i = 1; i <= n; i++ )paint( 1, xcod[ lft[i] ], xcod[ rht[i] ], i );ans = 0;cal(1);printf("%d\n", ans);}return 0;}

无注释代码:

#pragmaG++ optimize("O2")#include <string.h>#include <stdlib.h>#include <stdio.h>#defineTRUE1#defineFALSE0#defineNONE0#defineMAXPOSTERN10001#defineMAXXCORD20001#defineMAXSEGSIZE65536#defineMAXCORD10000001typedefcharBOOL;typedefstruct {intlft;intrht;intcol;} Seg;intlft[MAXPOSTERN];intrht[MAXPOSTERN];BOOLbcl[MAXPOSTERN];intcord[MAXXCORD];intxcod[MAXCORD];Segs[MAXSEGSIZE];intans;voidbuild( int r, int lft, int rht ) {s[r].lft = lft;s[r].rht = rht;s[r].col = NONE;if ( lft == rht )return ;intlc;intmid;lc= r + r;mid = ( lft + rht ) >> 1;build( lc, lft, mid );build( lc + 1, mid + 1, rht );}voidpaint( int r, int lft, int rht, int col ) {if ( lft == s[r].lft && rht == s[r].rht ) {s[r].col = col;return ;}intlc, rc;intmid;lc= r + r;rc= lc + 1;mid = s[lc].rht;if ( s[r].col ) {s[lc].col = s[r].col;s[rc].col = s[r].col;s[r].col  = NONE;}if ( rht <= mid ) {paint( lc, lft, rht, col );return ;}if ( lft > mid ) {paint( rc, lft, rht, col );return ;}paint( lc, lft, mid, col );paint( rc, mid + 1, rht, col );}voidcal(int r) {intcol;col= s[r].col;if (col) {if ( !bcl[col] ) {ans++;bcl[col] = TRUE;}return ;}intlc;lc = r + r;cal(lc);cal( lc + 1 );}intfcmp(const void *a, const void *b) {return *(int *)a - *(int *)b;}intmain() {intc;intn;inti, j;scanf("%d", &c);while ( c-- ) {scanf("%d", &n);memset(bcl + 1, FALSE, n * sizeof(BOOL));for ( i = 1, j = 1; i <= n; i++, j++ ) {scanf("%d%d", lft + i, rht + i);cord[j++] = lft[i];cord[j]  = rht[i];}qsort(cord + 1, n + n, sizeof(int), &fcmp);for ( j = 1, i = 1; j <= n + n; j++, i++ ) {cord[i]= cord[j];xcod[ cord[i] ] = i;while ( j < n + n && cord[j] == cord[j + 1] )j++;}build( 1, 1, i - 1 );for ( i = 1; i <= n; i++ )paint( 1, xcod[ lft[i] ], xcod[ rht[i] ], i );ans = 0;cal(1);printf("%d\n", ans);}return 0;}

STL优化:

注释代码:

/*             * Problem ID : POJ 2528 Mayor's posters   * Author     : Lirx.t.Una             * Language   : G++        * Run Time   : 47 ms             * Run Memory : 33508 KB            */#pragma G++ optimize("O2")#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>#defineMAXPOSTN10000#defineMAXSEGSIZE65536#defineMAXCORD10000000#defineLFT(T)( (T) << 1 )#defineRHT(T)( LFT(T) | 1 )using namespace std;//lft and rht point of posters//每张海报的左右端点坐标intpl[MAXPOSTN + 1];intpr[MAXPOSTN + 1];//将所有端点坐标都保存在x中intx[1 + ( MAXPOSTN << 1 ) ];//将海报中出现的坐标都映射到一个小范围中以减小//树的大小inthash[MAXCORD + 1];//cover,即线段树//true表示该结点表示的区间被海报完全覆盖了,false表示没有被覆盖过boolcov[MAXSEGSIZE];boolpost( int tree, int al, int ar, int lft, int rht ) {//adding lft and rht,表示将海报[lft, rht]贴到//墙[lft, rht]中//!!注意,这里的算法是按照相反的顺序进行检查//即在算法中先将后面贴的海报反过来先贴到墙上//如果当前海报所占区域之前已经被其它海报覆盖过了则  //当前海报必然无法露在外面//已经被覆盖,所以[al, ar]无法露在外面if ( cov[tree] ) return false;//表示该区域没有被完全覆盖,因此当前海报必然可以露在外面一部分if ( lft == al && ar == rht ) return cov[tree] = true;intmid;boolres;mid = ( lft + rht ) >> 1;if ( ar <= mid )res = post( LFT(tree), al, ar, lft, mid );else if ( al > mid )res = post( RHT(tree), al, ar, mid + 1, rht );else {boolbl, br;//!!!注意,不能res = bl_post() || br_post()//因为||具有短路特性,br_post不一定执行,这会导致右边可能没有被正常覆盖,从而影响后面的结果bl  = post( LFT(tree), al, mid, lft, mid );br  = post( RHT(tree), mid + 1, ar, mid + 1, rht );res = bl || br;//两边中只要有一边没被完全覆盖则表示该海报有一部分可以露在外面}cov[tree] = cov[ LFT(tree) ] && cov[ RHT(tree) ];//注意!!还需更新当前结点覆盖情况,update的传统操作!!//如果两边在之前的操作中都被覆盖了,则代表当前结点区间肯定也被完全覆盖了return res;}intmain() {intt;//测例数intn;//海报数intnn;//最终海报端点坐标不重复的个数inti;//计数变量intans;scanf("%d", &t);while ( t-- ) {memset(cov, false, sizeof(cov));//相当于build,初始化为全都没被覆盖scanf("%d", &n);nn = 0;//进行离散化for ( i = 1; i <= n; i++ ) {scanf("%d%d", pl + i, pr + i);x[nn++] = pl[i];x[nn++] = pr[i];}sort(x, x + nn);//排序nn = unique(x, x + nn) - x;//单一化for ( i = 0; i < nn; i++ ) hash[ x[i] ] = i + 1;//映射成更小的范围ans = 0;for ( i = n; i > 0; i-- )//!!!注意,从后往前贴!!!if ( post( 1, hash[ pl[i] ], hash[ pr[i] ], 1, nn ) )ans++;printf("%d\n", ans);}return 0;}
无注释代码:

#pragma G++ optimize("O2")#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>#defineMAXPOSTN10000#defineMAXSEGSIZE65536#defineMAXCORD10000000#defineLFT(T)( (T) << 1 )#defineRHT(T)( LFT(T) | 1 )using namespace std;intpl[MAXPOSTN + 1];intpr[MAXPOSTN + 1];intx[1 + ( MAXPOSTN << 1 ) ];inthash[MAXCORD + 1];boolcov[MAXSEGSIZE];boolpost( int tree, int al, int ar, int lft, int rht ) {if ( cov[tree] ) return false;if ( lft == al && ar == rht ) return cov[tree] = true;intmid;boolres;mid = ( lft + rht ) >> 1;if ( ar <= mid )res = post( LFT(tree), al, ar, lft, mid );else if ( al > mid )res = post( RHT(tree), al, ar, mid + 1, rht );else {boolbl, br;bl  = post( LFT(tree), al, mid, lft, mid );br  = post( RHT(tree), mid + 1, ar, mid + 1, rht );res = bl || br;}cov[tree] = cov[ LFT(tree) ] && cov[ RHT(tree) ];return res;}intmain() {intt;intn;intnn;inti;intans;scanf("%d", &t);while ( t-- ) {memset(cov, false, sizeof(cov));scanf("%d", &n);nn = 0;for ( i = 1; i <= n; i++ ) {scanf("%d%d", pl + i, pr + i);x[nn++] = pl[i];x[nn++] = pr[i];}sort(x, x + nn);nn = unique(x, x + nn) - x;for ( i = 0; i < nn; i++ ) hash[ x[i] ] = i + 1;ans = 0;for ( i = n; i > 0; i-- )if ( post( 1, hash[ pl[i] ], hash[ pr[i] ], 1, nn ) )ans++;printf("%d\n", ans);}return 0;}
单词解释:

poster:n, 海报,广告

mayor:n, 市长

citizen:n, 市民,公民

byte:n, 字节

can not stand that:不能忍受....

candidate:n, 候选人

mayoral:adj, 市长的

election:n, 选举

mayoral election:n, 市长选举

campaign:n, 竞选运动

electoral:adj, 选举的

electoral poster:n, 选举海报

whim:n, 一时兴起

at one;s whim:在某人一时兴起时

council:n, 委员会,地方议会

exactly:adv, 恰好的,精确的

segment:n, 段,部分

contiguous:adj, 连续的,接触的

widely:adv, 广泛的

differ in..:...在...方面不同

moreover:adv, 而且,此外

occupy:vt, 占领,占据

visible:adj, 可见的

subsequent:adj, 后来的,随后的

respectively:adv, 分别的,各自的

collegiate:adj, 大学的

Alberta:n, 地名,亚伯达,加拿大西部的一个省

0 0
原创粉丝点击