题解 排列

传送门
CF997E Good Subsegments

可以发现一个序列是好的的条件是 \(max-min=r-l\)
但这样只能判定,不好计数

  • 关于区间值域连续段计数:
    一个转化是转为对 \((max-min)-(r-l)\) 取到最小值的情况进行计数
    在线做法是析合树但我不会
    一个离线做法是将询问按右端点排序,扫描线按上式维护最小值及个数
    那么扫描到 \(r=i\) 时若最小值为 0,最小值个数就是以 r 为右端点的连续段数
    考虑若查询 \([l, r]\) 内的所有连续段怎么处理
    一个想法是对整棵线段树打标记,在每一个 r 处将每个节点的值加入历史答案
    于是定义 \(lock(p)\) 为节点 \(p\) 最后一次建立快照后还应再建立多少次快照
    注意此时 \(tag(p)\) 是上一次建立快照后积累的标记,所以要先下传 tag
    因为 spread 时一整套调整操作可能还没做完,所以不能判 val(p<<1)=0
    image

于是复杂度 \(O(n\log n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define fir first
#define sec second
#define pb push_back
#define ll long long
#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
int a[N];

// namespace force{
// 	set<int> s;
// 	int f[N][N];
// 	struct bits{
// 		int a[N];
// 		inline void add(int i, int dat) {for (; i<=n; i+=i&-i) a[i]+=dat;}
// 		inline int query(int i) {int ans=0; for (; i; i-=i&-i) ans+=a[i]; return ans;}
// 	}bit[N];
// 	void solve() {
// 		for (int i=1; i<=n; ++i) {
// 			s.clear();
// 			for (int j=i; j<=n; ++j) {
// 				s.insert(a[j]);
// 				if (*s.rbegin()-*s.begin()==j-i) ++f[i][j];
// 			}
// 		}
// 		for (int i=1; i<=n; ++i) for (int j=i; j<=n; ++j) f[i][j]+=f[i][j-1];
// 		for (int j=1; j<=n; ++j) for (int i=1; i<=j; ++i) bit[j].add(i, f[i][j]);
// 		for (int i=1,l,r; i<=m; ++i) {
// 			l=read(); r=read();
// 			printf("%d\n", bit[r].query(r)-bit[r].query(l-1));
// 		}
// 	}
// }

namespace task{
    vector<pair<int, int>> q[N];
    int sta1[N], sta2[N], top1, top2;
	int tl[N<<3], tr[N<<3], val[N<<3], tag[N<<3];
    ll cnt[N<<3], sum[N<<3], lock[N<<3], ans[N];
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#define val(p) val[p]
    #define sum(p) sum[p]
    #define tag(p) tag[p]
    #define cnt(p) cnt[p]
    #define lock(p) lock[p]
    inline void pushup(int p) {
        cnt(p)=0;
        val(p)=min(val(p<<1), val(p<<1|1));
        if (val(p<<1)==val(p)) cnt(p)+=cnt(p<<1);
        if (val(p<<1|1)==val(p)) cnt(p)+=cnt(p<<1|1);
    }
    inline void spread(int p) {
    	//cout<<"spread: "<<p<<endl;
    	val(p<<1)+=tag(p); tag(p<<1)+=tag(p);
        val(p<<1|1)+=tag(p); tag(p<<1|1)+=tag(p);
        if (val(p<<1)==val(p)) sum(p<<1)+=lock(p)*cnt(p<<1), lock(p<<1)+=lock(p);
    	if (val(p<<1|1)==val(p)) sum(p<<1|1)+=lock(p)*cnt(p<<1|1), lock(p<<1|1)+=lock(p);
    	lock(p)=tag(p)=0;
    	#if 0
    	if (!val(p<<1)) sum(p<<1)+=lock(p)*cnt(p<<1);
    	if (!val(p<<1|1)) sum(p<<1|1)+=lock(p)*cnt(p<<1|1);
        val(p<<1)+=tag(p); tag(p<<1)+=tag(p); lock(p<<1)+=lock(p);
        val(p<<1|1)+=tag(p); tag(p<<1|1)+=tag(p); lock(p<<1|1)+=lock(p);
        lock(p)=tag(p)=0;
        #endif
    }
    void build(int p, int l, int r) {
        tl(p)=l; tr(p)=r;
        if (l==r) {val(p)=INF; return ;}
        int mid=(l+r)>>1;
        build(p<<1, l, mid);
        build(p<<1|1, mid+1, r);
        pushup(p);
    }
    void upd(int p, int pos, int dat) {
       	if (tl(p)==tr(p)) {val(p)=0; cnt(p)=1; return ;}
        spread(p);
        int mid=(tl(p)+tr(p))>>1;
        if (pos<=mid) upd(p<<1, pos, dat);
        else upd(p<<1|1, pos, dat);
        pushup(p);
    }
    void upd(int p, int l, int r, int dat) {
    	//if (p==1) cout<<"upd: "<<l<<' '<<r<<' '<<dat<<endl;
        if (l<=tl(p)&&r>=tr(p)) {val(p)+=dat; tag(p)+=dat; return ;}
        spread(p);
        int mid=(tl(p)+tr(p))>>1;
        if (l<=mid) upd(p<<1, l, r, dat);
        if (r>mid) upd(p<<1|1, l, r, dat);
        pushup(p);
    }
    int query(int p, int l, int r) {
        if (l<=tl(p)&&r>=tr(p)) {
        	//cout<<"qsum: at "<<p<<' '<<tl(p)<<' '<<tr(p)<<" get "<<sum(p)<<endl;
        	return sum(p);
        }
        spread(p);
        int mid=(tl(p)+tr(p))>>1; ll ans=0;
        if (l<=mid) ans+=query(p<<1, l, r);
        if (r>mid) ans+=query(p<<1|1, l, r);
        return ans;
    }
    void locking(int p, int l, int r) {
    	//cout<<"lock: "<<p<<' '<<l<<' '<<r<<endl;
    	spread(p);
    	if (l<=tl(p)&&r>=tr(p)) {++lock(p); return ;}
    	int mid=(tl(p)+tr(p))>>1;
        if (l<=mid) locking(p<<1, l, r);
        if (r>mid) locking(p<<1|1, l, r);
    }
	void solve() {
		for (int i=1,l,r; i<=m; ++i) {
            l=read(); r=read();
            q[r].pb({l, i});
        }
        build(1, 1, n);
        for (int i=1; i<=n; ++i) {
        	//cout<<"i: "<<i<<endl;
            if (i>1) upd(1, 1, i-1, -1); upd(1, i, 1);
            while (top1 && a[sta1[top1]]<=a[i]) upd(1, sta1[top1-1]+1, sta1[top1], -a[sta1[top1]]), --top1;
            upd(1, sta1[top1]+1, i, a[i]); sta1[++top1]=i;
            while (top2 && a[sta2[top2]]>=a[i]) upd(1, sta2[top2-1]+1, sta2[top2], a[sta2[top2]]), --top2;
            upd(1, sta2[top2]+1, i, -a[i]); sta2[++top2]=i;
            //spread(1); locking(1, 1, i);
            ++lock(1); sum(1)+=cnt(1); spread(1);
            //cout<<"locknum: "<<lock(2)<<endl;
            //spread(1); spread(2);
			//cout<<val(5)<<endl;
			//if (i==4) cout<<val(3)<<endl;
            for (auto it:q[i]) ans[it.sec]=query(1, it.fir, i);
            //if (i==4) cout<<lock(7)<<endl;
            //cout<<"1: "<<val(1)<<' '<<cnt(1)<<endl;
        }
        for (int i=1; i<=m; ++i) printf("%lld\n", ans[i]);
	}
}

signed main()
{
	freopen("subsegment.in", "r", stdin);
	freopen("subsegment.out", "w", stdout);

	n=read();
	for (int i=1; i<=n; ++i) a[i]=read();
	m=read();
	task::solve();
	
	return 0;
}
posted @ 2022-02-24 20:11  Administrator-09  阅读(3)  评论(0编辑  收藏  举报