[CERC2017]Intrinsic Interval

题意

给出一个n排列,m次询问,每次查询长度最小的区间,使得这个区间排序后出现连续的整数(即相邻的差为1),并且包含(或等于)区间[l,r]。若长度相等,取l端点最小的。

n,m<=1E5


思考

重要的性质:

1.一个区间是连续的,当且仅当其存在r-l个无序二元组(x,y),满足|x-y|=1。

2.若两个连续区间有交,其交必然是连续的。因为交的部分要同时满足左右部分是连续的。若交不连续,至多满足一个部分连续。

根据性质2,可以知道对于某个询问,可以通过不断移动要求的右端点,直到出现的所有的连续区间至少有一个完全覆盖了它。此时长度最小的一定是最优的。

根据性质1,可以先离线,再依次将数组中的每个数产生的贡献加入线段树。具体地讲,对于数ai,若ai-1,ai+1出现的位置在i左侧,则在区间[1,位置ai-1],[1,位置ai+1]加1,表示多出了一个差为1的无序二元组。那只要知道哪些[l,i]满足vall+l=r即可(r-l=vall)。方便起见,最开始建树时vali=i,则只要查询vall=i。

由于一个区间满足条件的无序二元组最多为r-l个,维护最大值及其位置即可。

接下来是询问部分。离线之后,按r排序,每次加入r=i的询问至set(实际是multiset,因为有重)中。set中按l从大到小排序。这样一来,每次查询尽可能大的左端点,一旦无法覆盖就能break。

复杂度O(nlogn+mlogm)


代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int maxn=1E5+5;
  4 int n,m,a[maxn],ansX[maxn],where[maxn],ansY[maxn];
  5 int t[maxn*4],tag[maxn*4],maxVal[maxn*4],maxPos[maxn*4];
  6 struct query
  7 {
  8     int x,y,id;
  9     bool operator < (query A)const
 10     {
 11         if(x!=A.x)
 12             return x>A.x;
 13         return y<A.y;
 14     }
 15 }q[maxn];
 16 vector<query>wait[maxn];
 17 void pushdown(int l,int r,int num)
 18 {
 19     if(!tag[num])
 20         return;
 21     maxVal[num]+=tag[num];
 22     if(l==r)
 23     {
 24         tag[num]=0;
 25         return;
 26     }
 27     tag[num<<1]+=tag[num];
 28     tag[num<<1|1]+=tag[num];
 29     tag[num]=0;
 30 }
 31 void update(int l,int r,int num)
 32 {
 33     pushdown(l,r,num);
 34     if(l==r)
 35         return;
 36     int mid=(l+r)>>1;
 37     pushdown(l,mid,num<<1);
 38     pushdown(mid+1,r,num<<1|1);
 39     if(maxVal[num<<1]<=maxVal[num<<1|1])
 40     {
 41         maxVal[num]=maxVal[num<<1|1];
 42         maxPos[num]=maxPos[num<<1|1];
 43     }
 44     else
 45     {
 46         maxVal[num]=maxVal[num<<1];
 47         maxPos[num]=maxPos[num<<1];
 48     }
 49 }
 50 void build(int l,int r,int num)
 51 {
 52     if(l==r)
 53     {
 54         maxVal[num]=l;
 55         maxPos[num]=l;
 56         return;
 57     }
 58     int mid=(l+r)>>1;
 59     build(l,mid,num<<1);
 60     build(mid+1,r,num<<1|1);
 61     update(l,r,num);
 62 }
 63 void add(int L,int R,int l,int r,int x,int num)
 64 {
 65     update(l,r,num);
 66     if(L<=l&&r<=R)
 67     {
 68         tag[num]+=x;
 69         update(l,r,num);
 70         return;
 71     }
 72     if(r<L||R<l)
 73         return;
 74     int mid=(l+r)>>1;
 75     add(L,R,l,mid,x,num<<1);
 76     add(L,R,mid+1,r,x,num<<1|1);
 77     update(l,r,num);
 78 }
 79 int ask(int L,int R,int l,int r,int x,int num)
 80 {
 81     update(l,r,num);
 82     if(L<=l&&r<=R)
 83     {
 84         if(maxVal[num]!=x)
 85             return -1;
 86         return maxPos[num];
 87     }
 88     if(r<L||R<l)
 89         return -1;
 90     int mid=(l+r)>>1;
 91     return max(ask(L,R,l,mid,x,num<<1),ask(L,R,mid+1,r,x,num<<1|1));
 92 }
 93 void out(int l,int r,int num)
 94 {
 95     update(l,r,num);
 96     if(l==r)
 97     {
 98         cout<<maxVal[num]<<' ';
 99         return;
100     }
101     int mid=(l+r)>>1;
102     out(l,mid,num<<1);
103     out(mid+1,r,num<<1|1);
104 }
105 int main()
106 {
107     ios::sync_with_stdio(false);
108     cin>>n;
109     build(1,n,1);
110     for(int i=1;i<=n;++i)
111     {
112         cin>>a[i];
113         where[a[i]]=i;
114     }
115     cin>>m;
116     for(int i=1;i<=m;++i)
117     {
118         cin>>q[i].x>>q[i].y;
119         q[i].id=i;
120         wait[q[i].y].push_back(q[i]);
121     }
122     where[n+1]=where[0]=n+1;
123     multiset<query>S;
124     for(int i=1;i<=n;++i)
125     {
126         if(where[a[i]-1]<i)
127             add(1,where[a[i]-1],1,n,1,1);
128         if(where[a[i]+1]<i)
129             add(1,where[a[i]+1],1,n,1,1);
130         for(int j=0;j<wait[i].size();++j)
131         {
132 //            cout<<"NEW"<<wait[i][j].x<<' '<<wait[i][j].y<<endl;
133             S.insert(wait[i][j]);
134         }
135         while(!S.empty())
136         {
137             set<query>::iterator pt=S.begin();
138 //            cout<<(*pt).x<<' '<<(*pt).y<<" "<<S.size()<<"---"<<endl;
139             int pos=ask(1,(*pt).x,1,n,i,1);
140             if(pos==-1)
141                 break;
142             ansX[(*pt).id]=pos;
143             ansY[(*pt).id]=i;
144             S.erase(pt);
145         }
146     }
147     for(int i=1;i<=m;++i)
148         cout<<ansX[i]<<" "<<ansY[i]<<endl;
149     return 0;
150 }
View Code

猜你喜欢

转载自www.cnblogs.com/GreenDuck/p/10813207.html