[***]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 }
声讨某ex_face一干人等卡分快调块长卡掉数据