题目大意:定义一个序列为【不无聊的】当且仅当这个序列的任意一个区间都存在一个数只出现过一次,给定一个序列,要求判断这个序列是否是【不无聊的】
定义 lasti 表示第 i 个元素上一次出现的位置(第一次出现则为 0 ), nexti 表示第 i 个元素下一次出现的位置(最后一次出现则为 n+1 ),那么这个元素能成为某个区间仅出现一次的数,当且仅当这个区间的左端点在 [lasti+1,i] 之间,右端点在 [i,nexti−1] 之间
我们可以将区间的左右端点放在二维平面上,那么一个元素产生的贡献是一个矩形,我们要确定的是所有元素对应的矩形的并集是否是覆盖所有合法区间对应的点
显然线段树+扫描线就行了
写完卡时过你告诉我正解是暴力?????
#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;
int T;
struct Segtree{
Segtree *ls,*rs;
int min_val,mark;
void* operator new (size_t)
{
static Segtree mempool[M<<1],*C;
static int tim;
if(tim!=T)
tim=T,C=mempool;
C->ls=C->rs=0x0;
C->min_val=C->mark=0;
return C++;
}
void Add(int x)
{
min_val+=x;
mark+=x;
}
void Push_Up()
{
min_val=min(ls->min_val,rs->min_val);
}
void Push_Down()
{
if(mark)
{
ls->Add(mark);
rs->Add(mark);
mark=0;
}
}
void Build_Tree(int x,int y)
{
int mid=x+y>>1;
if(x==y)
return ;
(ls=new Segtree)->Build_Tree(x,mid);
(rs=new Segtree)->Build_Tree(mid+1,y);
}
void Modify(int x,int y,int l,int r,int val)
{
int mid=x+y>>1;
if(x==l&&y==r)
{
Add(val);
return ;
}
Push_Down();
if(r<=mid)
ls->Modify(x,mid,l,r,val);
else if(l>mid)
rs->Modify(mid+1,y,l,r,val);
else
ls->Modify(x,mid,l,mid,val) , rs->Modify(mid+1,y,mid+1,r,val) ;
Push_Up();
}
int Get_Min(int x,int y,int l,int r)
{
int mid=x+y>>1;
if(x==l&&y==r)
return min_val;
Push_Down();
if(r<=mid)
return ls->Get_Min(x,mid,l,r);
if(l>mid)
return rs->Get_Min(mid+1,y,l,r);
return min( ls->Get_Min(x,mid,l,mid) , rs->Get_Min(mid+1,y,mid+1,r) ) ;
}
}*tree;
struct abcd{
int pos,l,r,type;
bool operator < (const abcd &a) const
{
return pos < a.pos ;
}
}stack[M<<1];
int n,top;
int a[M],last[M],next[M];
map<int,int> pos;
void Initialize()
{
++T;top=0;tree=new Segtree;
}
void Insert(int x1,int x2,int y1,int y2)
{
stack[++top].pos=x1;
stack[ top].l=y1;
stack[ top].r=y2;
stack[ top].type=1;
stack[++top].pos=x2+1;
stack[ top].l=y1;
stack[ top].r=y2;
stack[ top].type=-1;
}
int main()
{
int T,i,j;
for(cin>>T;T;T--)
{
Initialize();
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
pos.clear();
for(i=1;i<=n;i++)
{
if(pos.find(a[i])==pos.end())
last[i]=1;
else
last[i]=pos[a[i]]+1;
pos[a[i]]=i;
}
pos.clear();
for(i=n;i;i--)
{
if(pos.find(a[i])==pos.end())
next[i]=n;
else
next[i]=pos[a[i]]-1;
pos[a[i]]=i;
}
for(i=1;i<=n;i++)
Insert(last[i],i,i,next[i]);
sort(stack+1,stack+top+1);
tree->Build_Tree(1,n);
for(j=1,i=1;i<=n;i++)
{
for(;j<=top&&stack[j].pos==i;j++)
tree->Modify(1,n,stack[j].l,stack[j].r,stack[j].type);
if(tree->Get_Min(1,n,i,n)==0)
break;
}
if(i==n+1)
puts("non-boring");
else
puts("boring");
}
return 0;
}