1 2 3 4

CodeForces - 1437E Make It Increasing 线段树动态开点

https://codeforces.com/problemset/problem/1437/E

 

这是有限制的最长上升子序列

数字之间必须满足list[i] - list[j] >= i - j

处理的时候就是让list[i] - i,这样就得到了最长不下降子序列,非正数就赋成INF忽略不计,就可以算了,见到大佬门用upper_bounder算的,不太会

我就用权值线段树动态开点写了这个题,转换成最长不下降子序列最重要!!!

具体看代码,不好写但是原理很简单

#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 1e6+1111;
typedef long long ll;
ll len = 3e9+11;

struct Node{
	int l,r,ans;
}tree[maxn*10];

ll INF = 2e9+3;

int cnt = 0;
int update(int& node,ll be,ll en,ll i,int val){
	if(node == 0) node = ++cnt;
	int mid = be + en >> 1;
	if(be == en){
		tree[node].ans = val;
		return 0;
	}
	if(i <= mid) update(tree[node].l,be,mid,i,val);
	else update(tree[node].r,mid+1,en,i,val);
	int l = tree[node].l;
	int r = tree[node].r;
	tree[node].ans = max(tree[l].ans,tree[r].ans);
	return 0;
}
int ask(int node,ll be,ll en,ll LL,ll RR){
	if(node == 0)  return 0;
	int mid = be + en >> 1;
	if(LL <= be && en <= RR) {
		return tree[node].ans;
	}
	int val1 = -1,val2 = -1;
	if(LL <= mid) val1 = ask(tree[node].l,be,mid,LL,RR);
	if(RR > mid) val2 = ask(tree[node].r,mid+1,en,LL,RR);
	return max(val1,val2);
}

ll list[maxn];
int ins[maxn];
ll cns[maxn];
int dp[maxn];

int n,k;
int init(){
	for(int i=0;i<=cnt;i++){
		tree[i].l = tree[i].r = 0;
		tree[i].ans = 0;
	}
	cnt = 2;
	return 0;
}

int cal(int l,int r,int f){
	int root =1;
	cnt = 2;
	int ans = 0;
	int be = l + 1,en = r;
	int len = 2e9;

	for(int i=be;i<=en;i++){
		cns[i] = list[i] - list[l] - (i - be);
		if(cns[i] <= 0) {
			cns[i] = INF;
			ans++;
		}
	}
	
	ans = 0;
	for(int i = be;i<=en;i++){
		if(cns[i] == INF) continue;
		
		int a = ask(root,1,len,1,cns[i]);	
		dp[i] = a+1;
		ans = max(ans,dp[i]);
		update(root,1,len,cns[i],dp[i]);
	}
	
	for(int i=0;i<=cnt;i++){
		tree[i].l = tree[i].r = tree[i].ans = 0;
	}
	
	if(f) return r - l - ans;
	return r - l - dp[en];
}

int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%lld",&list[i]);
	}
	list[0] = -1000000002;
	
	int f = 0;
	for(int i=1;i<=k;i++){
		scanf("%d",&ins[i]);
	}
	
	for(int i=2;i<=k;i++){
		int x = ins[i];
		int y = ins[i-1];
		if(list[x] - list[y] < x - y){
			f = 1;
			break;
		}
	}
	if(f){
		printf("-1\n");
		return 0;
	}
	if(k == 0){
		int ans = cal(0,n,1);
		cout<<ans<<endl;
		return 0;
	}
	int ans = 0;

	for(int i=2;i<=k;i++){
		ans += cal(ins[i-1],ins[i],0);
	}	
	
	ans += cal(ins[k],n,1);
	ans += cal(0,ins[1],0);
	cout<<ans<<endl;
	return 0;
}
/*
100 0
4 20 52 2 7 36 8 73 9 99 13 19 14 89 32 2 6 2 16 21 47 22 66 23 25 95 28 
4 29 64 30 31 7 48 32 51 35 37 77 57 40 42 56 40 43 44 46 13 47 12 48 49 
24 51 69 53 54 98 21 57 59 61 62 52 63 30 68 32 69 39 8 67 71 59 72 81 76 
77 11 82 85 14 83 33 86 89 89 90 43 96 91 31 93 69 58 94 45 96 2 99

输出 80 

*/

  

 

posted @ 2020-10-30 13:41  Lesning  阅读(81)  评论(0编辑  收藏  举报