URAL 1019. Line Painting (线段树)

来源:互联网 发布:简单html静态网站源码 编辑:程序博客网 时间:2024/05/22 06:42

方法一:用链表存区间,每次上色的操作,依次取出所有的区间,用上色的区间去覆盖,返回新的区间。

由于每次都要遍历一遍所有的区间,比方法二慢。


方法二:离散化的线段树

先把所有区间的端点列出来,排序。

然后用线段树来做,最后将连续的白色区间合并,再计算答案。

代码写的比较乱。



方法一代码:

#define FOR(i,n) for(long long (i)=1;(i)<=(n);(i)++)#define For(i,n) for(long long (i)=0;(i)<(n);(i)++)using namespace std;struct Node{int L,R;//横坐标 bool Flag;//这段是黑1,白0 Node *next;}; Node *List; //区间链表的头指针 int N;Node *NewList=NULL,*NewEnd=NULL;void Insert(int a,int b,bool v); //区间上色 void Add(Node *T);//将T加入新链表 Node *AddIn(int a,int b,bool v);//辅助函数,生成一个 区间的结构体。 int main(void){while(cin>>N){Node *temp=new Node;List=NULL;temp->L=0;temp->R=1000000000;temp->Flag=0;temp->next=List;List=temp;For(i,N) {int a,b;char c;cin>>a>>b>>c;Insert(a,b,c=='b');}int Max=-1;int L=-1,R=-1;//搜索所有区间,找最长的区间。temp=List;while(temp){if(!temp->Flag) if(temp->R-temp->L>Max) Max=temp->R-temp->L,L=temp->L,R=temp->R; temp=temp->next;}printf("%d %d\n",L,R);}return 0;}void Insert(int a,int b,bool v){NewList=NULL;NewEnd=NULL;int T=0;//是否已经完成操作。 while(List){//取出一个元素 Node *temp=List;List=List->next;if(T || (temp->R < a) ) {Add(temp); continue;}//比较是否需要更改,将结果加入新链表 if(b <=temp->R){if(temp->Flag!=v){//分割成3区间Add(AddIn(temp->L,a,temp->Flag));Add(AddIn(a,b,v));Add(AddIn(b,temp->R,temp->Flag));T=1;continue;}else{Add(temp);//不操作,直接放回T=1;continue;}}else{if(temp->Flag!=v){Add(AddIn(temp->L,a,temp->Flag));Add(AddIn(a,temp->R,v));a=temp->R;}else{a=temp->R;Add(temp);}}}List=NewList;}void Add(Node *T){if(T==NULL) return;T->next=NULL;if(NewEnd){if(NewEnd->R==T->L){if(NewEnd->Flag==T->Flag){NewEnd->R=T->R;delete T;return;}}NewEnd->next=T;NewEnd=T;NewEnd->next=NULL;}else{NewList=T;NewEnd=T;NewEnd->next=NULL;}}Node *AddIn(int a,int b,bool v){if(a>=b) return NULL;Node *temp=new Node;temp->L=a,temp->R=b,temp->Flag=v;temp->next=NULL;return temp;}

方法二代码:

#include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <algorithm>#include <map>#define  inf  0x5fffffff#define PN 10010  //点数 #define ls l,m,rt<<1#define rs m+1,r,rt<<1|1using namespace std;struct P{int x;bool operator <(const P&B)const{return x<B.x;}}p[PN];int Pn;struct Seg{int l,r;bool v;void set(int l,int r){this->l=l;this->r=r;}}s[PN];struct Node{//点int v;//黑1 白0  混色-1 }node[PN <<2];int N;void PushDown(int rt){if(~node[rt].v){//如果是纯色 node[rt<<1].v=node[rt].v;node[rt<<1|1].v=node[rt].v;node[rt].v=-1;}}void build(int l,int r,int rt){if(l==Pn) return;if(l==r){node[rt].v=0;return;}int m=(l+r)>>1;build(ls);build(rs);node[rt].v=0;}void insert(int L,int R,bool v,int l,int r,int rt){if(l==Pn) return;if(L <=p[l].x && p[r].x <R){node[rt].v=v;return;}if(l==r&&p[r].x==R) return;PushDown(rt);int m=(l+r)>>1;if(L <=p[m].x) insert(L,R,v,ls);if(R > p[m].x) insert(L,R,v,rs); }int Sn;void FullSearch(int l,int r,int rt){ if(l==Pn) return;if(l==r){if(!node[rt].v){s[Sn++].set(p[l].x,p[l+1].x);}return;}PushDown(rt);int m=(l+r)>>1;FullSearch(ls);FullSearch(rs);}int main(void){while(cin>>N){//建立所有的端点 Pn=3;map<int,int> MP;p[1].x=0;p[2].x=1000000000;FOR(i,N) {int a,b;char c;scanf("%d%d %c",&s[i].l,&s[i].r,&c);s[i].v=c=='b';int I;//用map来判重,去掉重复的端点。 if(MP.count(s[i].l)) I=MP[s[i].l];else MP[s[i].l]=Pn++,I=MP[s[i].l],p[I].x=s[i].l;if(MP.count(s[i].r)) I=MP[s[i].r];else MP[s[i].r]=Pn++,I=MP[s[i].r],p[I].x=s[i].r;}MP.clear();Pn--;//排序 sort(p+1,p+Pn+1);//建立线段树,初始化为白色 build(1,Pn,1);//进行区间上色 FOR(i,N) insert(s[i].l,s[i].r,s[i].v,1,Pn,1);//,OUT1(i),FullSearch(1,Pn,1);//OUT3(s[i].l,s[i].r,s[i].v);Sn=1;//搜索所有区间,将白色的存入 s数组 FullSearch(1,Pn,1);int Cur=1;//合并相邻的白色区间 for(int i=2;i<Sn;i++){if(s[Cur].r==s[i].l){s[Cur].r=s[i].r;}else{Cur++;s[Cur]=s[i];}}//搜索最长的白色区间。 Seg ANS=s[1];for(int i=2;i<=Cur;i++){if(s[i].r-s[i].l>ANS.r-ANS.l){ANS=s[i];}}//输出答案 printf("%d %d\n",ANS.l,ANS.r);}return 0;}




 



0 0
原创粉丝点击