zoukankan      html  css  js  c++  java
  • [***]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
    ",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一干人等卡分快调块长卡掉数据

  • 相关阅读:
    函数柯里化
    常用正则
    校验table行内的form编辑
    前端代码 读取excel表格数据
    cocos2d-x 帧动画学习
    Linux 下vim配置
    Android开发笔记 二
    cocos2d-x CCDictionary类学习
    Android开发笔记
    Cococs2d-x移植到Window下的问题
  • 原文地址:https://www.cnblogs.com/Al-Ca/p/11306657.html
Copyright © 2011-2022 走看看