您的位置:首页 > 其它

POJ 2528 - Mayor's posters

2012-07-23 09:43 357 查看
题目地址 : http://poj.org/problem?id=2528

PS: 其实代码还是还是很水的。有个地方可以优化但不知怎么优化。

这题RE了很多次,貌似是题目数据超范围了?但是我用 if(n>maxn)while(1);来检测,并没有TLE~~
而我范围确实是开了4*maxn。。。后来直接开 8*maxn(很奇怪的是,发现下面的错误之后,改正之后不RE了~~ 囧~


但是这样还是WA了~~ 看了discuss,终于发现了一组错误数据~~~ 查看之后,发现是离散化出问题~~

因为是线段覆盖,按先后顺序覆盖3个线段 1~10、1~4
、7~10,其中5~6的空间是第一条线段的。而离散化之后,变成了 1~4、1~2、3~4,因此第一条线段完全被遮住了~~~~~ 囧哭了~~

之前以为用的方法搓了,所以还写了另一个。现在有两种方法。

方法一:每个线段都有一个val。线段覆盖,每次更新,将之前的覆盖过的线段重复部分覆盖掉,即区间赋值为val。最后计算的时候,查询有多少个不同的val。

方法二:每个线段都保存一个长度,每次更新,将区间标记成该次更新的线段的标号。下次更新时,如果有重复部分,就找到重复部分的已存在的线段标号,将该标号所代表的线段长度减去此重复区间的长度。那么,如果最后还有长度剩余,就表示没有被完全覆盖。

于是最后统计的时候,只需要找到有多少个len大于0的线段即可。

//方法一:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll (v<<1)
#define rr (v<<1|1)
#define tmid ((l+r)>>1)
using namespace std;

const int maxn=11000;

int flag[maxn*16];
bool vis[maxn];
int n,nn,cnt,sum;
int s[maxn*2],res[maxn*2],dir[maxn*2];

int cmp(int a,int b){
return s[a]<s[b];
}
void deal(){
int i;
nn=n<<1;
for(i=0;i<nn;i++) dir[i]=i;
sort(dir,dir+nn,cmp);
//	for(i=0;i<nn;i++) cout<<dir[i]<<" ";cout<<endl;
res[dir[0]]=cnt=1;
for(i=1;i<nn;i++)
if(s[dir[i]]==s[dir[i-1]])
res[dir[i]]=cnt;
else if(s[dir[i]]>s[dir[i-1]]+1) res[dir[i]]=(cnt+=2);
else res[dir[i]]=(cnt+=1);
//	for(i=0;i<n;i++) cout<<res[i]<<" "<<res[i+n]<<endl;
memset(vis,false,sizeof(vis));
}

void make_tree(int l,int r,int v){
flag[v]=-1;
if(l==r) return;
make_tree(l,tmid,ll);
make_tree(tmid+1,r,rr);
}
void update(int val,int li,int ri,int l,int r,int v){
if(li>r || ri<l) return;
if(li<=l && r<=ri){
flag[v]=val;
return;
}
if(l==r) while(1);
if(flag[v]!=-2){
flag[ll]=flag[rr]=flag[v];
flag[v]=-2;
}

update(val,li,ri,tmid+1,r,rr);
update(val,li,ri,l,tmid,ll);
}
int query(int l,int r,int v){
if(flag[v]==-1) return 0;
if(flag[v]>=0){
if(vis[flag[v]]) return 0;
vis[flag[v]]=true;
return 1;
}
return query(l,tmid,ll)+query(tmid+1,r,rr);
}

int main(){
int t,i;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d%d",&s[i],&s[n+i]);
deal();
make_tree(1,cnt,1);
for(i=0;i<n;i++)
update(i,res[i],res[i+n],1,cnt,1);
printf("%d\n",query(1,cnt,1));
}
return 0;
}

/*

3
3
5 6
4 5
6 8
3
1 10
1 3
6 10
5
1 4
2 6
8 10
3 4
7 10

*/


//方法二:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll (v<<1)
#define rr (v<<1|1)
#define tmid ((l+r)>>1)
using namespace std;

const int maxn=11000;

int flag[maxn*16];
int len[maxn];
int n,nn,cnt,sum;
int s[maxn*2],res[maxn*2],dir[maxn*2];

int cmp(int a,int b){
return s[a]<s[b];
}
void deal(){
int i;
nn=n<<1;
for(i=0;i<nn;i++) dir[i]=i;
sort(dir,dir+nn,cmp);
//	for(i=0;i<nn;i++) cout<<dir[i]<<" ";cout<<endl;
res[dir[0]]=cnt=1;
for(i=1;i<nn;i++)
if(s[dir[i]]==s[dir[i-1]])
res[dir[i]]=cnt;
else if(s[dir[i]]>s[dir[i-1]]+1) res[dir[i]]=(cnt+=2);
else res[dir[i]]=(cnt+=1);
//	for(i=0;i<n;i++) cout<<res[i]<<" "<<res[i+n]<<endl;
memset(len,0,sizeof(len));
}

void make_tree(int l,int r,int v){
flag[v]=-1;
if(l==r) return;
make_tree(l,tmid,ll);
make_tree(tmid+1,r,rr);
}
void update(int val,int li,int ri,int l,int r,int v){
if(ri<l || li>r) return;
if(li<=l && r<=ri){
if(flag[v]>=0)
len[flag[v]]-=r-l+1;
else if(flag[v]==-2){
update(val,li,ri,l,tmid,ll);
update(val,li,ri,tmid+1,r,rr);
}
flag[v]=val;
return ;
}
if(flag[v]!=-2){
flag[ll]=flag[rr]=flag[v];
flag[v]=-2;
}
update(val,li,ri,l,tmid,ll);
update(val,li,ri,tmid+1,r,rr);
}

int main(){
int t,i;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d%d",&s[i],&s[n+i]);
deal();
make_tree(1,cnt,1);
for(i=0;i<n;i++)
update(i,res[i],res[i+n],1,cnt,1),len[i]=res[i+n]-res[i]+1;
for(sum=0,i=0;i<n;i++)
if(len[i]>0) sum++;
printf("%d\n",sum);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: