BZOJ2080 : [Poi2010]Railway

如果存在$k$使得$i<j<k$,且$a[k]<a[i]<a[j]$,那么$i$和$j$不能在一个栈中。

设$b[i]=\min(a[i..n])$,如果$b[j]<a[i]<a[j]$,那么$i$和$j$不能在一个栈中。

设$c[i]$表示最大的$j$,满足$b[j]<i$,则$i$要向位置在$[i+1,c[a[i]]]$之间所有$a[j]>a[i]$的$j$连边,还要向$a$在$[b[i]+1,a[i]-1]$里所有位置$<i$的$j$连边。

然后二分图染色即可,最后检查是否合法。

在染色的时候,维护两棵线段树,第一棵按位置维护$a$的最大值,第二棵按$a$维护位置的最小值,即可不重不漏地取出所有没有染过色的点,每次取出一个点就要将它从两棵树中删除。

时间复杂度$O(n\log n)$。

#include<cstdio>
const int N=100010,M=262150;
int n,i,j,a[N],b[N],c[N],f[N],va[M],vb[M],pos[N],tmp,col[N],bit[3][N];
inline void read(int&a){char c;while(!(((c=getchar())>=‘0‘)&&(c<=‘9‘)));a=c-‘0‘;while(((c=getchar())>=‘0‘)&&(c<=‘9‘))(a*=10)+=c-‘0‘;}
inline int min(int a,int b){return a<b?a:b;}
inline int mergea(int x,int y){
  if(!x||!y)return x+y;
  return a[x]>a[y]?x:y;
}
inline int mergeb(int x,int y){
  if(!x||!y)return x+y;
  return x<y?x:y;
}
void build(int x,int a,int b){
  if(a==b){
    pos[a]=x;
    va[x]=a;
    vb[x]=f[a];
    return;
  }
  int mid=(a+b)>>1;
  build(x<<1,a,mid),build(x<<1|1,mid+1,b);
  va[x]=mergea(va[x<<1],va[x<<1|1]);
  vb[x]=mergeb(vb[x<<1],vb[x<<1|1]);
}
void aska(int x,int a,int b,int c,int d){
  if(c<=a&&b<=d){tmp=mergea(tmp,va[x]);return;}
  int mid=(a+b)>>1;
  if(c<=mid)aska(x<<1,a,mid,c,d);
  if(d>mid)aska(x<<1|1,mid+1,b,c,d);
}
void askb(int x,int a,int b,int c,int d){
  if(c<=a&&b<=d){tmp=mergeb(tmp,vb[x]);return;}
  int mid=(a+b)>>1;
  if(c<=mid)askb(x<<1,a,mid,c,d);
  if(d>mid)askb(x<<1|1,mid+1,b,c,d);
}
inline void del(int x){
  int y=pos[x];
  for(va[y]=0,y>>=1;y;y>>=1)va[y]=mergea(va[y<<1],va[y<<1|1]);
  y=pos[a[x]];
  for(vb[y]=0,y>>=1;y;y>>=1)vb[y]=mergeb(vb[y<<1],vb[y<<1|1]);
}
void dfs(int x,int y){
  del(x);
  col[x]=y;
  int l=i+1,r=c[a[x]];
  if(l<=r)while(1){
    tmp=0;
    aska(1,1,n,l,r);
    if(!tmp)break;
    if(a[tmp]<a[x])break;
    dfs(tmp,3-y);
  }
  l=b[x]+1,a[x]-1;
  if(l<=r)while(1){
    tmp=0;
    askb(1,1,n,l,r);
    if(!tmp)break;
    if(tmp>x)break;
    dfs(tmp,3-y);
  }
}
inline void add(int*b,int x){for(;x<=n;x+=x&-x)b[x]++;}
inline int ask(int*b,int x){int t=0;for(;x;x-=x&-x)t+=b[x];return t;}
int main(){
  read(n);
  for(i=1;i<=n;i++)read(a[i]),f[a[i]]=i;
  for(b[n]=a[n],i=n-1;i;i--)b[i]=min(a[i],b[i+1]);
  for(i=1;i<=n;c[i++]=j)while(j<n&&b[j+1]<i)j++;
  build(1,1,n);
  for(i=1;i<=n;i++)if(!col[i])dfs(i,1);
  for(i=1;i<=n;i++){
    if(ask(bit[col[i]],a[i]-1)>ask(bit[col[i]],b[i]))return puts("NIE"),0;
    add(bit[col[i]],a[i]);
  }
  for(puts("TAK"),i=1;i<=n;i++)printf("%d%c",col[i],i<n?‘ ‘:‘\n‘);
  return 0;
}

  

时间: 2024-08-19 08:49:17

BZOJ2080 : [Poi2010]Railway的相关文章

BZOJ 2080: [Poi2010]Railway 双栈排序

2080: [Poi2010]Railway Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 140  Solved: 35[Submit][Status][Discuss] Description 一个铁路包含两个侧线1和2,右边由A进入,左边由B出去(看下面的图片) 有n个车厢在通道A上,编号为1到n,它们被安排按照要求的顺序(a1,a2,a3,a4....an)进入侧线,进去还要出来,它们要按照编号顺序(1,2,3,4,5....n)从通道B

单调队列 BZOJ 2096 [Poi2010]Pilots

2096: [Poi2010]Pilots Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 819  Solved: 418[Submit][Status][Discuss] Description Tz又耍畸形了!!他要当飞行员,他拿到了一个飞行员测试难度序列,他设定了一个难度差的最大值,在序列中他想找到一个最长的子串,任意两个难度差不会超过他设定的最大值.耍畸形一个人是不行的,于是他找到了你. Input 输入:第一行两个有空格隔开的整数k(0

BZOJ 2086: [Poi2010]Blocks

2086: [Poi2010]Blocks Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 494  Solved: 222[Submit][Status][Discuss] Description 给出N个正整数a[1..N],再给出一个正整数k,现在可以进行如下操作:每次选择一个大于k的正整数a[i],将a[i]减去1,选择a[i-1]或a[i+1]中的一个加上1.经过一定次数的操作后,问最大能够选出多长的一个连续子序列,使得这个子序列的每个数

BZOJ2086: [Poi2010]Blocks

题解: 想了想发现只需要求出最长的一段平均值>k即可. 平均值的问题给每个数减去k,判断是否连续的一段>0即可. 然后我们发现如果i<j 且 s[i]<s[j],那么 j 对于l>j不会比i 优. 那我们就可以维护一个单调的s[i],然后对于每个l去二分出它的答案. 但这样会T. 再次考虑单调性. 如果 l>j,且s[l]>s[i],那么我们的答案最小也是l-i,所以j必须取比i小的s才有可能更新答案.然后就可以两个指针扫一遍了. 好吧 我承认我口胡... 代码:

洛谷 P3507 [POI2010]GRA-The Minima Game

P3507 [POI2010]GRA-The Minima Game 题目描述 Alice and Bob learned the minima game, which they like very much, recently. The rules of the game are as follows. A certain number of cards lies on a table, each inscribed with a positive integer. The players m

【BZOJ2090/2089】[Poi2010]Monotonicity 2 动态规划+线段树

[BZOJ2090/2089][Poi2010]Monotonicity Description 给出N个正整数a[1..N],再给出K个关系符号(>.<或=)s[1..k].选出一个长度为L的子序列(不要求连续),要求这个子序列的第i项和第i+1项的的大小关系为s[(i-1)mod K+1].求出L的最大值. Input 第一行两个正整数,分别表示N和K (N, K <= 500,000).第二行给出N个正整数,第i个正整数表示a[i] (a[i] <= 10^6).第三行给出K

bzoj2079[Poi2010]Guilds*

bzoj2079[Poi2010]Guilds 题意: 给一个图染色,要求每个图必须染上某个色同时与另外一个色的点有边相连,问可否满足要求.n≤200000. 题解: 直接上结论:除非有点没有与别的点相连,否则肯定能满足要求. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 #define inc(i,j,k) for(int i

bzoj2096[Poi2010]Pilots*

bzoj2096[Poi2010]Pilots 题意: 给一个序列和一个最大值,要求找一个最长连续子串,使里面任意两个数相差不超过这个最大值.序列大小≤3000000 题解: 用两个单调队列,分别维护当前区间的最大值和最小值,然后用双指针法. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) for(int i=j;i<=k;i++) 5

bzoj 2084: [Poi2010]Antisymmetry -- manacher

2084: [Poi2010]Antisymmetry Time Limit: 10 Sec  Memory Limit: 259 MB Description 对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串.比如00001111和010101就是反对称的,1001就不是.现在给出一个长度为N的01字符串,求它有多少个子串是反对称的. Input 第一行一个正整数N (N <= 500,000).第二行一个长度为N的01字符串. Output