方法一:用链表存区间,每次上色的操作,依次取出所有的区间,用上色的区间去覆盖,返回新的区间。
由于每次都要遍历一遍所有的区间,比方法二慢。
方法二:离散化的线段树
先把所有区间的端点列出来,排序。
然后用线段树来做,最后将连续的白色区间合并,再计算答案。
代码写的比较乱。
方法一代码:
#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|1 using 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; }