#include<bits/stdc++.h>
using namespace std;
const int maxn = 0x3f3f3f3f;
int mn[200010];
int cost[200010];
int dp[200010];
vector<int>v[200010];
void add_edge(int l,int r,int iend)
{
if(l==r)
{
mn[iend]=maxn;
return ;
}
int mid=(l+r)/2;
add_edge(l,mid,iend<<1);
add_edge(mid+1,r,(iend<<1)+1);
mn[iend]=min(mn[iend<<1],mn[(iend<<1)+1]);
}
int query(int left,int right,int l,int r,int iend)//区间查找
{
if(left<=l&&r<=right)
return mn[iend];
int mid=(l+r)/2;
int res=maxn;
if(left<=mid)
res=min(res,query(left,right,l,mid,iend<<1));//二分查找
if(right>mid)
res=min(res,query(left,right,mid+1,r,(iend<<1)+1));
return res;
}
void update(int pos,int val,int l,int r,int iend)//区间更新
{
if(l==r)
{
mn[iend]=min(mn[iend],val);
return;
}
int mid=(l+r)>>1;
if(pos<=mid)
update(pos,val,l,mid,iend<<1);//二分
else
update(pos,val,mid+1,r,(iend<<1)+1);
mn[iend]=min(mn[iend<<1],mn[(iend<<1)+1]);
}
int main()
{
int n,q;
int cnt=0;
scanf("%d",&n);
add_edge(1,n,1);
for(int i=1,j;i<=n;i++)
{
scanf("%d",&j);
cnt+=!j;//b中0的个数
cost[i]=j?1:-1;//当前bi为1即为1,bi为0即为-1,在加和前x位时即可得到bi为1的数量减去bi为零的数量
}
scanf("%d",&q);
for(int i=0,j,k;i<q;i++)
{
scanf("%d%d",&j,&k);
v[j].push_back(k);//存下区间
}
memset(dp,maxn,sizeof(dp));
dp[0]=0;
for(int i=1;i<=n;i++)
{
int ct = v[i].size();//左端点为i的区间的个数
for (int k = 0; k < ct;k++)
{
int j=v[ct][k];//右端点
int tmp=dp[i-1];
tmp=min(tmp,query(max(i-1,1)/*i为1时仍为1,其他为i-1*/,j,1,n,1));
if(tmp<dp[j])//存在更优解
{
dp[j]=tmp;
update(j,tmp,1,n,1);
}
}
dp[i]=min(dp[i],dp[i-1]+cost[i]);//cost[i]为1表示b[i]=1,cost[i]为-1表示b[i]=0,由于dp[i]表示a0b1-a0b0
}
printf("%d\n",dp[n]+cnt);//cnt表示b0的数量
return 0;
}
/*题目要求求min{(a=0&&b=1)+(a=1&&b=0)},即求min{(a=0&&b=1)+(b=0)-(a=0&&b=0)},
即求b=0+min{(a=0&&b=1)-(a=0&&b=0)},dp[i]表示前i个数的min{(a=0&&b=1)-(a=0&&b=0)}*/
ARC085F(动态规划,线段树)
猜你喜欢
转载自www.cnblogs.com/ldudxy/p/9466106.html
今日推荐
周排行