把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

UOJ #515. 【UR #19】前进四

题面传送门

UOJ是真的引领时代潮流。

首先显然有一个线段树维护区间单调栈的方法,但是是\(O(m\log ^2n)\)的并不够优秀。因为我们不需要知道区间的信息,我们只需要知道后缀的信息。

考虑离线,按照序列顺序从后往前维护时间轴,每次相当于区间取\(\min\),以及单点询问被真正取\(\min\)的次数。这个可以用一个Segment Beats解决。

什么,你不会Segment Beats?

这个是一种维护区间取\(\min\)的数据结构,具体的,你需要在线段树上每个区间维护两个值,\(mx\)表示最大值,\(se\)表示次大值。每次修改先把线段树上对应\(\log n\)个区间抠出来,然后分类讨论:

若当前取\(\min\)的值\(z\geq mx\),则这次修改对这个区间没有影响,可以直接返回。

\(se<z<mx\),则打上标记,表示将最大值改为\(z\),并将修改次数加一。

\(z\leq se\),则继续递归。

可以用势能分析证明复杂度为\(O(n+m\log n)\),记\(g_x\)为线段树上\(x\)节点对应的子树内的不同种类的数的数量,则每次继续递归会使区间内不同的值得数量至少减一,而不完全包含的节点则会至多\(+1\),总势能增加量不超过\(O(m\log n)\),因此复杂度\(O(n+m\log n)\)

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=1e6+5,M=N*4+5,K=2e3+5,mod=998244353,Mod=mod-1;const db eps=1e-5;const int INF=1e9+7;
struct IO{
    static const int S=1<<21;
    char buf[S],*p1,*p2;int st[105],Top;
    ~IO(){clear();}
    inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
    inline void pc(const char c){Top==S&&(clear(),0);buf[Top++]=c;}
    inline char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    inline IO&operator >> (char&x){while(x=gc(),x==' '||x=='\n'||x=='\r');return *this;}
    template<typename T>inline IO&operator >> (T&x){
        x=0;bool f=0;char ch=gc();
        while(ch<'0'||ch>'9'){if(ch=='-') f^=1;ch=gc();}
        while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=gc();
        f?x=-x:0;return *this;
    }
    inline IO&operator << (const char c){pc(c);return *this;}
    template<typename T>inline IO&operator << (T x){
        if(x<0) pc('-'),x=-x;
        do{st[++st[0]]=x%10,x/=10;}while(x);
        while(st[0]) pc('0'+st[st[0]--]);return *this;
    }
}fin,fout;
int n,m,A[N],Op[N],X[N],y,Ans[N];vector<int> D[N],Q[N];
namespace SB{
	#define ls v<<1
	#define rs v<<1|1
	int Mx[M],Se[M],Y[M];void PF(int v,int x,int y){x<Mx[v]&&(Mx[v]=x,Y[v]+=y);}void P(int v){Y[v]&&(PF(ls,Mx[v],Y[v]),PF(rs,Mx[v],Y[v]),Y[v]=0);}
	void Up(int v){Mx[v]=max(Mx[ls],Mx[rs]);Se[v]=-INF;min(Mx[ls],Mx[rs])^Mx[v]&&(Se[v]=min(Mx[ls],Mx[rs]));Se[v]=max(Se[v],max(Se[ls],Se[rs]));}
	void BD(int l=0,int r=m,int v=1){Mx[v]=INF;Se[v]=-INF;if(l==r)return;int m=l+r>>1;BD(l,m,ls);BD(m+1,r,rs);}
	void Ins(int x,int y,int z,int l=0,int r=m,int v=1){if(Mx[v]<=z) return;if(x<=l&&r<=y&&z>Se[v]) return PF(v,z,1);int m=l+r>>1;P(v);x<=m&&(Ins(x,y,z,l,m,ls),0);y>m&&(Ins(x,y,z,m+1,r,rs),0);Up(v);}
	int Qry(int x,int l=0,int r=m,int v=1){if(l==r) return Y[v];int m=l+r>>1;P(v);return x<=m?Qry(x,l,m,ls):Qry(x,m+1,r,rs);}
	void print(int l=0,int r=m,int v=1){if(l==r){printf("%d %d %d\n",l,Mx[v],Y[v]);return;}int m=l+r>>1;P(v);print(l,m,ls);print(m+1,r,rs);}
	#undef ls
	#undef rs
}
int main(){
	freopen("1.in","r",stdin);
	int i,j;fin>>n>>m;for(i=1;i<=n;i++) fin>>A[i];for(i=1;i<=m;i++) fin>>Op[i]>>y,Op[i]^2?fin>>X[i],D[y].PB(i):Q[y].PB(i);
	SB::BD();for(i=n;i;i--){X[0]=A[i];y=0;for(int j:D[i]) SB::Ins(y,j-1,X[y]),y=j;SB::Ins(y,m,X[y]);for(int j:Q[i]) Ans[j]=SB::Qry(j);/*printf("%d\n",i);SB::print();Pc('\n');*/}for(i=1;i<=m;i++) Op[i]^1&&(fout<<Ans[i]<<'\n',0);
} 
posted @ 2022-08-28 14:21  275307894a  阅读(299)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end