【NOIP模拟赛】公主的朋友 区间染色问题

这道题大家都用的分块,然而我发现这是一个经典算法:区间染色问题。

我们区间染色时把区间分成若干连续的颜色段,然后我们每次染色删除原来的颜色段插入新的颜色段。

我们发现我们的时间复杂度直接与我们要染色区间内的颜色段数有关,而且颜色段数就等于我们要处理的区间内的分界点+1,我们可以证明我们处理的分界点数最多n+m:一开始我们假设有n个不同的区间(即所有相邻颜色都不相同),并且我们每次染色都产生两个新的分界点(即每次染色都与两边区间内的颜色不同),那么我们产生的分界点数最多n+m。

我用的是set处理颜色段因此时间复杂度O((n+m)log(n))。

STL:set的erase如果你是按迭代器删的那么那个迭代器就是个野指针了....

#include <set>
#include <cstdio>
inline void read(int &sum){
  register char ch=getchar();
  for(sum=0;ch<'0'||ch>'9';ch=getchar());
  for(;ch>='0'&&ch<='9';sum=(sum<<1)+(sum<<3)+ch-'0',ch=getchar());
}
struct Segment{
  int l,r,key;
  inline friend bool operator < (Segment a,Segment b); 
};
int temp[100010],n,T,m;
inline bool operator < (Segment a,Segment b){
  return a.l<b.l;
}
std::set<Segment> Seg;
std::set<Segment>::iterator A,B;
int main(){
  read(n),read(m);
  for(int i=1;i<=n;i++)read(temp[i]);
  for(int i=1;i<=n;i++){
    int k=1;
    while(temp[i+k]==temp[i])k++;
    Seg.insert((Segment){i,i+k-1,temp[i]});
    i+=k-1;
  }
  int T;
  read(T);
  while(T--){
    int x,y,ans=0,key=0;
    read(x),read(y);
    Segment p=(Segment){x,x,0};
    A=Seg.upper_bound(p);
    p=(Segment){y,y,0};
    B=Seg.upper_bound(p);
    A--;
    key=A->key;
    ans-=x-A->l+1;
    x=A->l;
    B--;
    if(B->r!=y&&B->key==key)ans-=B->r-y;
    if(B->r!=y)Seg.insert((Segment){y+1,B->r,B->key});
    B++;
    while(A!=B){
      if(A->key==key)
        ans+=A->r-A->l+1;
      Seg.erase(A++);
    }
    Seg.insert((Segment){x,y,key});
    printf("%d
",ans);
  }
}
原文地址:https://www.cnblogs.com/TSHugh/p/7341222.html