zoukankan      html  css  js  c++  java
  • [Ynoi2015]纵使日薄西山

    题目大意:

    给定一个序列,每次单点修改,然后进行询问。

    定义一次操作为,选择一个位置$x$,将这个位置的数和左边、右边两个位置的数(不存在则忽略)各减去1,然后和0取max。

    对序列中最大的位置进行一次操作(相同则取最前面的),不断重复,直到所有位置为0为止。

    问执行了多少次操作。

    询问互相独立(即下一次询问的序列并不是全0)。

    解题思路:

    在太阳西斜的这个世界里,置身天上之森。等这场战争结束之后,不归之人与望眼欲穿的众人, 人人本着正义之名,长存不灭的过去、逐渐消逝的未来。我回来了,纵使日薄西山,即便看不到未来,此时此刻的光辉,盼君勿忘。————世界上最幸福的女孩

    我的愿望是,和珂朵莉一样可爱。


    淦不动辣QaQ就窝一个在那瞎分块

    一开始的做法是先分块,求出块内的答案,然后瞎分类讨论(自闭了QAQ)。

    实际上这个性质挺优美的为啥窝就是发现不了啊

    显然一次对某个位置操作到底,和答案是一样的(当你选择这个数进行操作后,其左边和右边就永远不会被操作。而其他数对这个位置无影响)。

    所以相当于求所有会被操作的位置上的数的和。

    考虑一个单调递增或单调递减的序列,在这上面选的数一定是一个选一个不选(奇偶性相同)。

    所以我们对奇数、偶数位置分别用树状数组维护一下,然后用set记录序列的极大、极小值的位置。则可以快速计算出两个极值之间的区间的贡献。

    然后对于单点修改,对受到影响的部分区间重新计算贡献即可。

    细节挺多的,比如对极小值是否取到的考虑(仅当其左右两个极大值的位置的奇偶性和这个极小值位置相同时,才能取到这个值)。

    时间复杂度$O(nlog n)$。

    C++ Code:

    #include<cstdio>
    #include<set>
    const int N=1e5+6;
    typedef long long LL;
    int n,a[N];
    struct BIT{
    	LL b[N];
    	inline void add(int i,int x){for(;i<N;i+=i&-i)b[i]+=x;}
    	inline LL ask(int i){LL x=0;for(;i;i^=i&-i)x+=b[i];return x;}
    }odd,even;
    std::set<int>s;
    LL ans=0;
    LL get(int x){
    	if(x<1||x>n)return 0;
    	auto it=s.find(x);
    	if(*it==1){
    		auto nxt=it;++nxt;
    		if(a[*it]<a[*nxt]){
    			if(*nxt&1)return odd.ask(*nxt-1)-odd.ask(*it-1);else
    				return even.ask(*nxt-1)-even.ask(*it-1);
    		}else return 0;
    	}
    	if(*it==n){
    		auto pre=it;--pre;
    		if(a[*pre]>=a[*it]){
    			if(*pre&1)return odd.ask(*it)-odd.ask(*pre-1);else
    				return even.ask(*it)-even.ask(*pre-1);
    		}else return a[n];
    	}
    	auto pre=it,nxt=it;--pre,++nxt;
    	if(a[*pre]>=a[*it]&&a[*it]<a[*nxt]){
    		LL ret=0;
    		if(*pre&1)ret+=odd.ask(*it-1)-odd.ask(*pre-1);else
    			ret+=even.ask(*it-1)-even.ask(*pre-1);
    		if(*nxt&1)ret+=odd.ask(*nxt-1)-odd.ask(*it);else
    			ret+=even.ask(*nxt-1)-even.ask(*it);
    		if((*pre&1)==(*it&1)&&(*nxt&1)==(*it&1))ret+=a[*it];
    		return ret;
    	}else return 0;
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i)
    		scanf("%d",a+i),((i&1)?odd:even).add(i,a[i]);
    	s.insert(-2),s.insert(-1),s.insert(n+2),s.insert(n+3);
    	s.insert(1);
    	for(int i=2;i<n;++i)
    		if(a[i-1]<a[i]&&a[i]>=a[i+1]||a[i-1]>=a[i]&&a[i]<a[i+1])s.insert(i);
    	s.insert(n);
    	for(int i:s)
    		ans+=get(i);
    	int q;
    	for(scanf("%d",&q);q--;){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		int nxt=*s.upper_bound(x),pre=*--s.lower_bound(x);
    		ans-=get(nxt),ans-=get(pre);
    		nxt=*s.upper_bound(nxt),pre=*--s.lower_bound(pre);
    		ans-=get(nxt),ans-=get(pre);
    		if(s.count(x))ans-=get(x),s.erase(x);
    		s.erase(x-1),s.erase(x+1);
    		if(x&1)odd.add(x,-a[x]),odd.add(x,y);else
    			even.add(x,-a[x]),even.add(x,y);
    		a[x]=y; 
    		for(int i=x-1;i<=x+1;++i){
    			if(i<1||i>n)continue;
    			if(i==1||i==n)s.insert(i);else
    				if(a[i-1]<a[i]&&a[i]>=a[i+1]||a[i-1]>=a[i]&&a[i]<a[i+1])s.insert(i);
    		}
    		for(auto l=s.find(pre),r=s.upper_bound(nxt);l!=r;++l)
    			ans+=get(*l);
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
  • 相关阅读:
    jmeter中生成不重复的序列
    jmeter返回解密
    jmeter请求加密
    查看链接设备和安装软件
    jmeter_事物控制器_Transaction Controller
    jmeter返回中提取匹配多个参数($1$$2$)
    jmeter官方文档地址
    DEDECMS会员注册如何配置邮箱发送邮件功能
    颤抖吧,Css3
    html embed用法
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/10602966.html
Copyright © 2011-2022 走看看