求帮忙卡常
查看原帖
求帮忙卡常
103333
Undefined_R楼主2021/11/12 11:36
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
inline namespace usual{
    #define space ' '
    #define endl '\n'
    template<typename T>T max(T a,T b){return a>b?a:b;}
    template<typename T>T min(T a,T b){return a<b?a:b;}
    inline long long input(){
        long long a=0,f=1;
        char tmp=getchar();
        while(!isdigit(tmp)){if(tmp=='-')f=-1;tmp=getchar();}
        while(isdigit(tmp)){a=(a<<3)+(a<<1)+(tmp^48);tmp=getchar();}
        return a*f;
    }
    class out{
        private:
            void output(long long x){
                if(x<0)putchar('-'),x=-x;
                if(x>9)output(x/10);
                putchar(x%10+48);
            }
            void output(int x){
                if(x<0)putchar('-'),x=-x;
                if(x>9)output(x/10);
                putchar(x%10+48);
            }
            void output(char t){
                putchar(t);
            }
            void output(const char *t){
                while(*t)putchar(*(t++));
            }
        public:
            template<class T>out operator<<(T x){
                output(x);
                return *this;
            }
    }opt;
} 
#define int long long
template<int _size>class segment_tree{//要支持:区间改值,区间查找 
	private:
		struct node{
			int l,r,maxx,minx,flag=-1;
			int size(){return r-l+1;}
		}t[_size<<2|1];
	public:
		void update(int p){
			t[p].maxx=max(t[p<<1].maxx,t[p<<1|1].maxx);
			t[p].minx=min(t[p<<1].minx,t[p<<1|1].minx);
		}
		void spread(int p){
			if(t[p].flag==-1)return;
			t[p<<1].maxx=t[p<<1].minx=t[p<<1].flag=t[p].flag;
			t[p<<1|1].maxx=t[p<<1|1].minx=t[p<<1|1].flag=t[p].flag;
			t[p].flag=-1;
		}
		void build(int p,int l,int r,int a[]){
			t[p].l=l,t[p].r=r;
			if(l==r){t[p].minx=t[p].maxx=a[l];return;}
			int mid=l+r>>1;
			build(p<<1,l,mid,a);
			build(p<<1|1,mid+1,r,a);
			update(p);
		}
		void change(int p,int l,int r,int val){
			if(l>r)return;
			if(l<=t[p].l&&t[p].r<=r){
				t[p].minx=t[p].maxx=val;
				t[p].flag=val;
				return;
			}
			spread(p);
			if(l<=t[p<<1].r)change(p<<1,l,r,val);
			if(r>=t[p<<1|1].l)change(p<<1|1,l,r,val);
			update(p);
		}
		int querymax(int p,int l,int r){
			if(l<=t[p].l&&t[p].r<=r)return t[p].maxx;
			spread(p);
			int res=0;
			if(l<=t[p<<1].r)res=max(res,querymax(p<<1,l,r));
			if(r>=t[p<<1|1].l)res=max(res,querymax(p<<1|1,l,r));
			return res;
		}
		int querymin(int p,int l,int r){
			if(l<=t[p].l&&t[p].r<=r)return t[p].minx;
			spread(p);
			int res=0x7fffffff;
			if(l<=t[p<<1].r)res=min(res,querymin(p<<1,l,r));
			if(r>=t[p<<1|1].l)res=min(res,querymin(p<<1|1,l,r));
			return res;
		}
};
segment_tree<100000>T;
/*
维护一个数列,初始时有n个元素
每次删除掉其中一个元素,然后问最大子段和
n≤100000

应该是水题
看某个元素所属子段

开个数组t[],t[i]表示点i的元素所属子段的编号
删元素:找到t[i],二分其左右端点,新建两个子段,然后把其左右子段给重新染色,线段树维护,
并且要标记原先的那个子段已经失效
再用个堆维护长度最大值即可 

*/
struct segment{
	int p,val;
	bool operator<(segment x)const{
		return this->val<x.val;
	}
};
std::priority_queue<segment>Q;
int n,a[100001],t[100001],sum[100001],cnt;
bool flag[1000001];
void read(){
	n=input();
	for(int i=1;i<=n;i++)
		a[i]=input();
}
void answer(){
	for(int i=1;i<=n;i++){
		int q=input();
		flag[T.querymax(1,q,q)]=1;
		int low=1,high=q,l,r;
		while(low<=high){
			int mid=low+high>>1;
			if(T.querymax(1,mid,q)==T.querymin(1,mid,q))high=mid-1;
			else low=mid+1;
		}
		l=low;
		low=q,high=n;
		while(low<=high){
			int mid=low+high>>1;
			if(T.querymax(1,q,mid)==T.querymin(1,q,mid))low=mid+1;
			else high=mid-1;
		}
		r=high;
		T.change(1,l,q-1,++cnt);
		Q.push({cnt,sum[q-1]-sum[l-1]});
		T.change(1,q+1,r,++cnt);
		Q.push({cnt,sum[r]-sum[q]});
		int ans=0;
		while(Q.size()&&flag[Q.top().p])Q.pop(); 
		if(Q.size()){ans=Q.top().val;}
		opt<<ans<<endl;
	}
}
void pre(){
	cnt++;
	for(int i=1;i<=n;i++){
		sum[i]=sum[i-1]+a[i];
		t[i]=cnt;
	}
	Q.push({cnt,sum[n]});
	T.build(1,1,n,t);
}
#undef int
int main(){
	read();
	pre();
	answer();
	return 0;
}

理论复杂度O(nlog2n)O(nlog^2n),但由于常数过于巨大实测当n=100000时不开优化开关要2.5s,开O2的话也要1.3s。。

2021/11/12 11:36
加载中...