zoukankan      html  css  js  c++  java
  • 吉司机线段树

    学了一下吉老师的在某年WC的讲的线段树。

    特来总结,学习一番.

    PDF地址:吉老师的Segment tree Beats!

    楔子:给出一个数列A 每次让某个区间中的(a_i)对x取min 询问某个区间的和。

    (n,mleq 500000)

    由于存在多次询问 我们进行标记永久化也没什么用 如果是一次的话我可以每次把标记标记到区间 最后求值即可。

    这里要引出吉司机线段树了。

    做法:线段树维护区间最大值mx 最大值次数 T 次大值 se 维护区间和 sum

    当某个区间要对x取min时 显然 mx<=x直接跳过这个区间 se<x<mx时 直接修改打上标记然后退出。

    最坏的情况 x<se 此时我们暴力递归子区间。

    通过吉老师的证明 这复杂度最坏是mlog^2的!

    具体证明:自己看pdf... 好吧听说吉老师证明是萎的 具体证明看国家集训队论文 时间复杂度 每次修改时间复杂度为log^2

    说了这么多了 上例题/cy

    bzoj 4695最假女选手

    虽然很复杂 但是 还是要码的 要迎男而上 男上加男?

    //#include<bitsstdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 2000000000
    #define ld long double
    #define pb push_back
    #define put(x) printf("%d
    ",x)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define pii pair<ll,ll> 
    #define F first
    #define mk make_pair
    #define mod 64123
    #define RE register
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define l(p) t[p].l
    #define r(p) t[p].r
    #define sum(p) t[p].sum
    #define mx(p) t[p].mx
    #define mn(p) t[p].mn
    #define sx(p) t[p].sx
    #define sn(p) t[p].sn
    #define tag(p) t[p].tag
    #define cx(p) t[p].cx
    #define cn(p) t[p].cn
    #define zz p<<1
    #define yy p<<1|1
    #define ls p<<1,l,r
    #define rs p<<1|1,l,r
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
    	return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
    	RE int x=0,f=1;char ch=getc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    	return x*f;
    }
    const int MAXN=500010;
    int n,Q;
    struct wy
    {
    	int l,r,tag;
    	ll sum;
    	int mx,sx,cx;
    	int mn,sn,cn;
    }t[MAXN<<2];
    inline void pushup(int p)
    {
    	sum(p)=sum(zz)+sum(yy);
    	if(mx(zz)>mx(yy))mx(p)=mx(zz),cx(p)=cx(zz),sx(p)=max(mx(yy),sx(zz));
    	if(mx(yy)>mx(zz))mx(p)=mx(yy),cx(p)=cx(yy),sx(p)=max(mx(zz),sx(yy));
    	if(mx(zz)==mx(yy))mx(p)=mx(zz),cx(p)=cx(zz)+cx(yy),sx(p)=max(sx(zz),sx(yy));
    	if(mn(zz)<mn(yy))mn(p)=mn(zz),cn(p)=cn(zz),sn(p)=min(mn(yy),sn(zz));
    	if(mn(yy)<mn(zz))mn(p)=mn(yy),cn(p)=cn(yy),sn(p)=min(mn(zz),sn(yy));
    	if(mn(zz)==mn(yy))mn(p)=mn(zz),cn(p)=cn(zz)+cn(yy),sn(p)=min(sn(zz),sn(yy));
    }
    inline void build(int p,int l,int r)
    {
    	l(p)=l;r(p)=r;
    	if(l==r)
    	{
    		mn(p)=mx(p)=get(sum(p));
    		cn(p)=cx(p)=1;
    		sx(p)=-INF;sn(p)=INF;
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(zz,l,mid);
    	build(yy,mid+1,r);
    	pushup(p);
    }
    inline void pushdown(int p)
    {
    	int mid=(l(p)+r(p))>>1;
    	if(tag(p))
    	{
    		int x=tag(p);tag(p)=0;
    		mx(zz)+=x;tag(zz)+=x;mn(zz)+=x;sx(zz)+=x;sn(zz)+=x;sum(zz)+=(ll)(mid-l(p)+1)*x;
    		mx(yy)+=x;tag(yy)+=x;mn(yy)+=x;sx(yy)+=x;sn(yy)+=x;sum(yy)+=(ll)(r(p)-mid)*x;
    	}
    	if(mx(p)<mx(zz))
    	{
    		if(mn(zz)==mx(zz))mn(zz)=mx(p);
    		if(sn(zz)==mx(zz))sn(zz)=mx(p);
    		sum(zz)-=(ll)(mx(zz)-mx(p))*cx(zz);
    		mx(zz)=mx(p);
    	}
    	if(mx(p)<mx(yy))
    	{
    		if(mn(yy)==mx(yy))mn(yy)=mx(p);
    		if(sn(yy)==mx(yy))sn(yy)=mx(p);
    		sum(yy)-=(ll)(mx(yy)-mx(p))*cx(yy);
    		mx(yy)=mx(p);
    	}
    	if(mn(p)>mn(zz))
    	{
    		if(mx(zz)==mn(zz))mx(zz)=mn(p);
    		if(sx(zz)==mn(zz))sx(zz)=mn(p);
    		sum(zz)+=(ll)(mn(p)-mn(zz))*cn(zz);
    		mn(zz)=mn(p);
    	}
    	if(mn(p)>mn(yy))
    	{
    		if(mx(yy)==mn(yy))mx(yy)=mn(p);
    		if(sx(yy)==mn(yy))sx(yy)=mn(p);
    		sum(yy)+=(ll)(mn(p)-mn(yy))*cn(yy);
    		mn(yy)=mn(p);
    	}
    }
    inline void change(int p,int l,int r,int x)
    {
    	if(l<=l(p)&&r>=r(p))
    	{
    		sum(p)+=(ll)(r(p)-l(p)+1)*x;
    		mx(p)+=x;mn(p)+=x;
    		sx(p)+=x;sn(p)+=x;
    		tag(p)+=x;return;
    	}
    	int mid=(l(p)+r(p))>>1;
    	pushdown(p);
    	if(l<=mid)change(ls,x);
    	if(r>mid)change(rs,x);
    	pushup(p);
    }
    inline void modifymax(int p,int l,int r,int x)
    {
    	if(mn(p)>=x)return;
    	if(l<=l(p)&&r>=r(p)&&sn(p)>x)
    	{
    		sum(p)+=(ll)(x-mn(p))*cn(p);
    		if(sx(p)==mn(p))sx(p)=x;
    		if(mx(p)==mn(p))mx(p)=x;
    		mn(p)=x;return;
    	}
    	int mid=(l(p)+r(p))>>1;
    	pushdown(p);
    	if(l<=mid)modifymax(ls,x);
    	if(r>mid)modifymax(rs,x);
    	pushup(p);
    }
    inline void modifymin(int p,int l,int r,int x)
    {
    	if(mx(p)<=x)return;
    	if(l<=l(p)&&r>=r(p)&&sx(p)<x)
    	{
    		sum(p)-=(ll)(mx(p)-x)*cx(p);
    		if(sn(p)==mx(p))sn(p)=x;
    		if(mn(p)==mx(p))mn(p)=x;
    		mx(p)=x;return;
    	}
    	int mid=(l(p)+r(p))>>1;
    	pushdown(p);
    	if(l<=mid)modifymin(ls,x);
    	if(r>mid)modifymin(rs,x);
    	pushup(p);
    }
    inline ll ask(int p,int l,int r)
    {
    	if(l<=l(p)&&r>=r(p))return sum(p);
    	int mid=(l(p)+r(p))>>1;
    	pushdown(p);ll cnt=0;
    	if(l<=mid)cnt+=ask(ls);
    	if(r>mid)cnt+=ask(rs);
    	return cnt;
    }
    inline int querymax(int p,int l,int r)
    {
    	if(l<=l(p)&&r>=r(p))return mx(p);
    	int mid=(l(p)+r(p))>>1;
    	pushdown(p);int cnt=-INF;
    	if(l<=mid)cnt=max(cnt,querymax(ls));
    	if(r>mid)cnt=max(cnt,querymax(rs));
    	return cnt;
    }
    inline int querymin(int p,int l,int r)
    {
    	if(l<=l(p)&&r>=r(p))return mn(p);
    	int mid=(l(p)+r(p))>>1;
    	pushdown(p);int cnt=INF;
    	if(l<=mid)cnt=min(cnt,querymin(ls));
    	if(r>mid)cnt=min(cnt,querymin(rs));
    	return cnt;
    }
    int main()
    {
    	freopen("1.in","r",stdin);
    	get(n);build(1,1,n);
    	get(Q);
    	rep(1,Q,i)
    	{
    		int op,x,y;
    		get(op);get(x);get(y);
    		if(op==1)change(1,x,y,read());
    		if(op==2)modifymax(1,x,y,read());
    		if(op==3)modifymin(1,x,y,read());
    		if(op==4)printf("%lld
    ",ask(1,x,y));
    		if(op==5)printf("%d
    ",querymax(1,x,y));
    		if(op==6)printf("%d
    ",querymin(1,x,y));
    	}
    	return 0;
    }
    

    一遍AC 再见 这又臭又长的代码 把我给写蒙蔽了 没想到这么长 尽管我已经极力压行了。。

    考虑标记问题 我们在下放标记是 有两类标记 可以发现 赋值标记可以被区间加标记给修改 区间加标记则不能被赋值标记修改。

    所以我们在进行区间修改时 我们把赋值标记修改后就相当于赋值标记后来 区间加标记先来这个顺序。

    所以再pushdown的时候也同样 先区间赋值 再单点赋值。

    需要注意的是 修改mx时会影响到mn sn,修改mn时可能会影响到mx sx.

  • 相关阅读:
    docker运行springboot应用
    docer运行node
    Git添加仓库
    安装docker-compose
    centos安装docker
    Centos设置软件源
    ubuntu安装docker
    ubuntu安装阿里云镜像地址
    docker加速器配置
    配置Spring发送邮件
  • 原文地址:https://www.cnblogs.com/chdy/p/12494507.html
Copyright © 2011-2022 走看看