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

    https://www.luogu.com.cn/problem/P5069

    首先对于最大的那个数,两侧的两数要跟着他一起下降,所以它们永远不会成为最大得到,那不妨直接让这个最大的减成 (0),同时,两侧两数也就也变成 (0)
    然后再去找下一个最大的
    所以只要求哪些数会成为当前最大的,计算它们的和即可,可以发现是对于每一个极大的单调区间,取第 (1,3,5,7....) 大的数
    然后想到这就不会维护了

    然后考虑怎么维护这个东西,首先用 set 记录下每一个极大(小)值点,然后对于每个极小值点,计算周围一个单调减、一个单调增区间的贡献即可(用一奇一偶两个线段树)
    需要注意一些边界问题
    再考虑单调修改以后怎么做,修改一个数,对与单调性最多只会对周围两个区间产生影响
    对于贡献,则要对于 在修改前的数组中,左右两侧分别第二个极值点 围城的区间中,按照修改后的数组重新计算
    这两点修改的影响应该还算好理解

    细节很烦,调了好久

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<set>
    #include<iomanip>
    #include<cstring>
    #define reg register
    #define EN puts("")
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=getchar();}
    	return y?x:-x;
    }
    #define N 100006
    int a[N];
    struct Tree{
    	struct Node{
    		Node *ls,*rs;
    		long long sum;
    	}dizhi[N*2],*root;
    	int tot;
    	void build(Node *tree,int l,int r){
    		if(l==r) return;
    		tree->ls=&dizhi[++tot];tree->rs=&dizhi[++tot];
    		int mid=(l+r)>>1;
    		build(tree->ls,l,mid);build(tree->rs,mid+1,r);
    	}
    	void change(Node *tree,int l,int r,int pos,int k){
    		if(l==r) return tree->sum=k,void();
    		int mid=(l+r)>>1;
    		if(pos<=mid) change(tree->ls,l,mid,pos,k);
    		else change(tree->rs,mid+1,r,pos,k);
    		tree->sum=tree->ls->sum+tree->rs->sum;
    	}
    	long long ask(Node *tree,int l,int r,int ql,int qr){
    		if(ql<=l&&r<=qr) return tree->sum;
    		int mid=(l+r)>>1;
    		long long ret=0;
    		if(ql<=mid) ret+=ask(tree->ls,l,mid,ql,qr);
    		if(qr>mid) ret+=ask(tree->rs,mid+1,r,ql,qr);
    		return ret;
    	}
    }odd,even;
    int n,m;
    std::set<int>set;
    long long get(int x){
    	if(x<1||x>n) return 0;
    	std::set<int>::iterator it=set.find(x),nex,pre;
    	nex=it;++nex;
    	pre=it;--pre;
    	//*it 应为极小值点
    	if(*it==1){
    		if(a[*it]<a[*nex]){
    			if((*nex)&1) return odd.ask(odd.root,1,n,1,(*nex)-1);
    			return even.ask(even.root,1,n,1,(*nex)-1);
    		}
    		return 0;
    	}
    	if(*it==n){
    		if(a[*it]<=a[*pre]){
    			if((*pre)&1) return odd.ask(odd.root,1,n,*pre,n);
    			return even.ask(even.root,1,n,*pre,n);
    		}
    		return a[n];//前一个极小值点并不会计算到 a[n]
    	}
    	if(a[*it]<=a[*pre]&&a[*it]<a[*nex]){
    		long long ret=0;
    		if((*pre)&1) ret+=odd.ask(odd.root,1,n,*pre,(*it)-1);
    		else ret+=even.ask(even.root,1,n,*pre,(*it)-1);
    		if((*nex)&1) ret+=odd.ask(odd.root,1,n,*(it)+1,(*nex)-1);
    		else ret+=even.ask(even.root,1,n,*(it)+1,(*nex)-1);
    		if(((*it)&1)==((*nex)&1)&&((*it)&1)==((*pre)&1)) ret+=a[*it];
    		return ret;
    	}
    	return 0;
    }
    int main(){
    	n=read();
    	odd.root=&odd.dizhi[0];even.root=&even.dizhi[0];
    	odd.build(odd.root,1,n);even.build(even.root,1,n);
    	for(reg int i=1;i<=n;i++){
    		a[i]=read();
    		if(i&1) odd.change(odd.root,1,n,i,a[i]);
    		else even.change(even.root,1,n,i,a[i]);
    	}
    	set.insert(-2);set.insert(-1);set.insert(n+2);set.insert(n+3);
    	set.insert(1);set.insert(n);
    	for(reg int i=2;i<n;i++)
    		if((a[i]>a[i-1]&&a[i]>=a[i+1])||(a[i]<=a[i-1]&&a[i]<a[i+1])) set.insert(i);
    	long long ans=0;
    	for(std::set<int>::iterator it=set.begin();it!=set.end();++it) ans+=get(*it);
    	m=read();
    	int x,y;
    	while(m--){
    		x=read();y=read();
    		int nex=*set.upper_bound(x),pre=*--set.lower_bound(x);
    		ans-=get(nex);ans-=get(pre);
    		nex=*set.upper_bound(nex);pre=*--set.lower_bound(pre);
    		ans-=get(nex);ans-=get(pre);
    		if(set.find(x)!=set.end()) ans-=get(x),set.erase(x);
    		set.erase(x-1);set.erase(x+1);//若 x-1 或 x+1 是极值点,则删除
    		if(x&1) odd.change(odd.root,1,n,x,y);
    		else even.change(even.root,1,n,x,y);
    		a[x]=y;
    		for(reg int i=x-1;i<=x+1;i++)if(i>=1&&i<=n){
    			if(i==1||i==n) set.insert(i);
    			else if((a[i]>a[i-1]&&a[i]>=a[i+1])||(a[i]<=a[i-1]&&a[i]<a[i+1])) set.insert(i);
    		}
    		for(std::set<int>::iterator it=set.find(pre),end=set.upper_bound(nex);it!=end;++it)
    			ans+=get(*it);
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    js原型链
    charles重放攻击2
    charles攻击重放测试网页
    js逆向基础知识
    js重放攻击
    js逆向之 中间人攻击-js注入
    修改jadx默认内存
    frida-ida hook操作
    关于ios 9系统完全越狱frida安装不上的的问题
    IDA 静态调试和动态调试
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/14147177.html
Copyright © 2011-2022 走看看