[***]HZOJ 优美序列

又是一道神仙题。考试的时候居然打了一个回滚莫队,不知道我咋想的……

先说一个某OJT80,洛谷T5分的思路(差距有点大):

可以把位置和编号映射一下,区间内最大值和最小值对应的位置,每次更新,直到找到符合条件的情况,复杂度玄学。最值的维护可以用ST表或者线段树,前者复杂度低些。

然后说正解吧:

先放出来看不懂的作者的正解:

分治法,离线处理。假设现在处理的询问都包含在[L,R] 中,设mid=(L+R)/2。然后将包含在[L,mid],[mid+1,R] 的区间分治处理。剩下的就是包含[mid,mid+1] [mid,mid+1]的询问,然后找出包含[mid,mid+1] [mid,mid+1]的所有优美区间,用这些优美区间更新询问的答案。

时间复杂度O(n(logn)^2)。

上面的我不会。

然后正解1:scc+线段树优化建图

但是我不会……

正解2:

扫描线+转化思想+线段树,虽然我不会扫描线(我还以为这玩意只能用到二维呢)……

1.好的区间的交也是好的区间

2.好的区间的并也是好的区间

好的区间的判断条件:maxn-minn=r-l,但是这样并不够,如果只是这样判断的话,就回到了80分的思路,不断拓展区间判断。

另一个判断条件是l+num=r,num为区间中形如(a,a+1)这样的点对数(将区间排序后就很显然了)。

所以我们离线将询问排序扔到set里,固定r,然后用线段树维护左边的信息及对应的l,令叶子节点的初始值为l,查询只需要找线段树中满足条件最靠右的,而每次r右移,给1~b[a[r]+-1]的区间的点对数+1,当然要判断一下,必须在它左边。

其实我开始有一个问题,如果固定r,能保证区间的右端点一定是r吗?显然是不能的,但是在处理r时,如果没有满足条件的l,这个询问就会被剩到set中,在r+1后继续更新,就保证了正确性。

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<set>
  5 #define LL long long
  6 #define MAXN 1000010
  7 using namespace std;
  8 struct ques
  9 {    
 10     int l,r,id;
 11     friend bool operator < (ques a,ques b)
 12     {return a.l==b.l?(a.r==b.r?a.id<b.id:a.r>b.r):a.l>b.l;}
 13 }q[MAXN];
 14 set<ques> s;
 15 set<ques>::iterator it;
 16 pair<int,int>ans[MAXN];
 17 int n,m,a[MAXN],b[MAXN];
 18 struct po
 19 {
 20     int mx,id;
 21     friend bool operator < (po a,po b)
 22     {return a.mx==b.mx?a.id<b.id:a.mx<b.mx;}
 23 };
 24 struct tree
 25 {
 26     po v;int ad,l,r;
 27     #define l(x) tr[x].l    
 28     #define r(x) tr[x].r
 29     #define ad(x) tr[x].ad
 30     #define v(x) tr[x].v
 31     #define ls(x) (x<<1)
 32     #define rs(x) (ls(x)+1)
 33 }tr[MAXN*4];
 34 void pushup(int x)
 35 {
 36     v(x)=max(v(ls(x)),v(rs(x)));
 37 }
 38 void down(int x)
 39 {    
 40     if(!ad(x))return;
 41     ad(ls(x))+=ad(x);
 42     ad(rs(x))+=ad(x);
 43     v(ls(x)).mx+=ad(x);
 44     v(rs(x)).mx+=ad(x);
 45     ad(x)=0;
 46 }
 47 void build(int x,int l,int r)
 48 {
 49     l(x)=l,r(x)=r;
 50     if(l==r)
 51     {v(x).id=v(x).mx=l;ad(x)=0;return;}
 52     int mid=(l+r)>>1;
 53     build(ls(x),l,mid);
 54     build(rs(x),mid+1,r);
 55     pushup(x);
 56 }
 57 void add(int x,int l,int r,int y)
 58 {
 59     if(l(x)>=l&&r(x)<=r)
 60     {v(x).mx+=y;ad(x)+=y;return;}
 61     down(x);
 62     int mid=(l(x)+r(x))>>1;
 63     if(l<=mid)add(ls(x),l,r,y);
 64     if(r>mid) add(rs(x),l,r,y);
 65     pushup(x);
 66 }
 67 po ask(int x,int l,int r)
 68 {
 69     down(x);
 70     if(l(x)>=l&&r(x)<=r)return v(x);
 71     int mid=(l(x)+r(x))>>1;po ans={-1,-1};
 72     if(l<=mid)ans=max(ans,ask(ls(x),l,r));
 73     if(r>mid) ans=max(ans,ask(rs(x),l,r));
 74     return ans;
 75 }
 76 bool cmp(ques a,ques b)
 77 {
 78     return a.r<b.r;
 79 }
 80 inline int read();
 81 signed main()
 82 {
 83 //    freopen("in.txt","r",stdin);
 84 
 85     n=read();
 86     for(int i=1;i<=n;i++)a[i]=read(),b[a[i]]=i;    
 87     m=read();
 88     for(int i=1;i<=m;i++)q[i].l=read(),q[i].r=read(),q[i].id=i;
 89     sort(q+1,q+m+1,cmp);    
 90     build(1,1,n);
 91     int ptr=1;    
 92     for(int i=1;i<=n;i++)
 93     {
 94         while(ptr<=m&&q[ptr].r==i)
 95             s.insert(q[ptr]),ptr++;
 96         if(a[i]>1&&b[a[i]-1]<i)add(1,1,b[a[i]-1],1);
 97         if(a[i]<n&&b[a[i]+1]<i)add(1,1,b[a[i]+1],1);
 98         while(s.size())
 99         {
100             ques now=*s.begin();
101             po tem=ask(1,1,now.l);
102             if(tem.mx!=i)break;
103             ans[now.id].first=tem.id;
104             ans[now.id].second=i;
105             s.erase(now);
106         }
107     }
108     for(int i=1;i<=m;i++)
109     printf("%d %d\n",ans[i].first,ans[i].second);
110 }
111 inline int read()
112 {
113     int s=0;char a=getchar();    
114     while(a<'0'||a>'9')a=getchar();
115     while(a>='0'&&a<='9'){s=s*10+a-'0',a=getchar();}
116     return s;
117 }
View Code

 声讨某ex_face一干人等卡分快调块长卡掉数据

posted @ 2019-08-06 21:43  Al_Ca  阅读(189)  评论(0编辑  收藏  举报
ヾ(≧O≦)〃嗷~