1. 程式人生 > >CC April 18 Cutting Plants 單調佇列+思維

CC April 18 Cutting Plants 單調佇列+思維

題意:長度為n的序列A,B.操作:選定一個區間[L,R]將裡面的數變為h , h<=min(a[L],a[L+1]...a[R]).
n<=1e5,1<=a[i],b[i]<=1e9. 問將序列A變為序列B最少需要多少次操作? 無解輸出-1.

假設某次操作是將[L,R]內的數變為x.
則x要滿足   max(b[i]) <= x <= min(a[i])  i=[L...R].

因為最多操作n次. 所以每一次操作[L,R,x] 這個x肯定等於某個 b[i]  i=[L;R].
同樣的某個點i.最後肯定會被某個[L,R,b[i]]操作到.

令val=b[1] b[1]前面沒有操作,顯然我們想讓後面更多b[j]=val被這一次操作到.
用一個單調佇列來維護,佇列中的元素x表示操作為[L,R,x]的可以進行到當前i.
若b[i]>b[j] 則佇列中的b[j]顯然不能在往後面操作.
若b[front]>a[i] a[i]不能變高,隊頭元素也不能往後操作.
此時若b[i]!=b[rear] 則當前位置要想變成b[i]必須新增一個操作(前面[l,r,x]的操作不可能跨到位置i)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int T,n,a[N],b[N];
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	cin>>T;
	while(T--){
		cin>>n;
		for(int i=1;i<=n;i++)	cin>>a[i];
		for(int i=1;i<=n;i++)	cin>>b[i];
		bool flag=true;
		for(int i=1;i<=n;i++)	if(a[i]<b[i])	flag=false;
		if(!flag){
			cout<<-1<<'\n';
			continue;
		}
		deque<int> q;
		int res=0;
		for(int i=1;i<=n;i++){
			while(!q.empty()&&b[i]>q.back())	q.pop_back();
			while(!q.empty()&&a[i]<q.front())	q.pop_front();
			if(a[i]!=b[i]&&(q.empty()||b[i]!=q.back())){
				res++;
				q.push_back(b[i]);
			}
		}
		cout<<res<<'\n';
	}
	return 0;
}