zoukankan      html  css  js  c++  java
  • CF1556E-Equilibrium【栈,树状数组】

    正题

    题目连接:https://codeforces.com/contest/1556/problem/E


    题目大意

    两个长度为(n)的序列(a,b)(q)次询问一个区间([l,r])

    在这个区间中你每次可以选择一个长度为偶数的下标递增的序列,让奇数位置的(a)加一,偶数位置的(b)(1)

    求最少操作次数使得每个(a_i=b_i)

    (n,qleq 10^5)


    解题思路

    视为一个减一个加的话,令(x_i=b_i-a_i)这样就变成了每个需要加/减的次数。

    可以视为每个减后面需要跟一个加,加前面需要跟一个减,而加后面可以免费跟一个减。

    把需要减的看成((),需要加的看成())的话就能看出来无论什么区间的情况下每个(()都是和同一个())匹配或者无法匹配。

    离线询问,开两个栈分别存(()()),然后一个树状数组用来记录每个位置需要的左端点位置上限,另一个记录每个左端点对应的权值即可。

    时间复杂度(O(nlog n+qlog n))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<stack>
    #define ll long long
    #define lowbit(x) (x&-x)
    using namespace std;
    const ll N=1e5+10;
    struct node{
    	ll l,r,id;
    }q[N];
    ll n,m,a[N],c[N],d[N],t[N],s[N],ans[N];
    stack<int> S,T;
    void Change(ll x,ll val){
    	x=n-x+1;
    	while(x<=n){
    		t[x]+=val;
    		x+=lowbit(x);
    	}
    	return;
    }
    ll Ask(ll x){
    	ll ans=0;x=n-x+1;
    	while(x){
    		ans+=t[x];
    		x-=lowbit(x);
    	}
    	return ans;
    }
    void Dhange(ll x,ll val){
    	x=n-x+1;
    	while(x<=n){
    		s[x]=min(s[x],val);
    		x+=lowbit(x);
    	}
    	return;
    }
    ll Bsk(ll x){
    	ll ans=n+1;x=n-x+1;
    	while(x){
    		ans=min(ans,s[x]);
    		x-=lowbit(x);
    	}
    	return ans;
    }
    bool cmp(node x,node y)
    {return x.r<y.r;}
    signed main()
    {
    	scanf("%lld%lld",&n,&m);
    	for(ll i=1;i<=n;i++)
    		scanf("%lld",&a[i]);
    	for(ll i=1,x;i<=n;i++)
    		scanf("%lld",&x),a[i]=x-a[i];
    	for(ll i=1;i<=m;i++)
    		scanf("%lld%lld",&q[i].l,&q[i].r),q[i].id=i;
    	sort(q+1,q+1+m,cmp);
    	memset(s,0x3f,sizeof(s));
    	c[0]=1e18;S.push(0);
    	for(ll i=1,z=1;i<=n;i++){
    		if(a[i]>0){
    			ll x=a[i];Change(i,x);
    			while(!T.empty()&&d[T.top()]<x)
    				x-=d[T.top()],Change(T.top(),-d[T.top()]),T.pop();
    			if(!T.empty())d[T.top()]-=x,Change(T.top(),-x);
    			S.push(i);c[i]=a[i];
    		}
    		if(a[i]<0){
    			ll x=-a[i];
    			while(c[S.top()]<x)
    				x-=c[S.top()],S.pop();
    			c[S.top()]-=x;Dhange(i,S.top());
    			if(c[S.top()]==0)S.pop();
    			T.push(i);d[i]=-a[i];
    		}
    		while(z<=m&&q[z].r==i){
    			if(q[z].l<=S.top()||q[z].l>Bsk(q[z].l))ans[q[z].id]=-1;
    			else ans[q[z].id]=Ask(q[z].l);
    			z++;
    		}
    		if(z>m)break;
    	}
    	for(ll i=1;i<=m;i++)
    		printf("%lld
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    一台电脑上的git同时使用两个github账户
    git自己操作命令组集合
    git基本原理
    js如何遍历表单所有控件
    js如何访问表单(四种方法)(博客园+li的方式去掉p标签)
    js如何操作表格(常用属性方法汇总)
    php数学和时间常用函数有哪些(总结表)(看学习视频效率挺高的)(复习)
    swift 笔记 (十九) —— 协议
    ecshop广告调用方法
    K60 启动过程分析
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15205641.html
Copyright © 2011-2022 走看看