列表

详情


NC17879. 线段树

描述

线段树是一种特殊的二叉树,满足以下性质:
每个点和一个区间对应,且有一个整数权值;
根节点对应的区间是[1,n];
如果一个点对应的区间是[l,r],且l<r,那么它的左孩子和右孩子分别对应区间[l,m]和[m+1,r],其中m=floor((l+r)/2)(floor表示向下取整);
如果一个点对应的区间是[l,r],且l=r,那么这个点是叶子;
如果一个点不是叶子,那么它的权值等于左孩子和右孩子的权值之和。

你需要维护一棵线段树,叶子的权值初始为0,接下来会进行m次操作:
操作1:给出l,r,a,对每个x(l≤x≤r),将[x,x]对应的叶子的权值加上a,非叶节点的权值相应变化;
操作2:给出l,r,a,询问有多少个线段树上的点,满足这个点对应的区间被[l,r]包含,且权值小于等于a。

输入描述

第一行两个整数n,m
接下来m行,每行包含四个整数op,l,r,a,表示一次操作,其中op表示操作类型
1≤n,m≤100000
1≤l≤r≤n
1≤op≤2
-100000≤a≤100000

输出描述

对每个操作2,输出一行,包含一个整数表示答案

示例1

输入:

3 3
1 2 3 9
2 1 2 1
2 1 3 1

输出:

1
1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 3325ms, 内存消耗: 5412K, 提交时间: 2019-02-28 16:47:40

#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define dep(i, a, b) for (int i = (a); i >= (b); --i)
#define mp make_pair
#define ft first
#define sc second
#define pb push_back
#define pii pair<int, int>
using namespace std;

int qreadInt() {
	int x = 0; char ch = getchar();
	while (!isdigit(ch)) ch = getchar();
	while (isdigit(ch)) (x *= 10) += (ch - '0'), ch = getchar();
	return x;
}

typedef long long i64;
const int N = 100010;
int _(int l, int r) {
    int x;
    assert(scanf("%d", &x) == 1 && l <= x && x <= r);
    return x;
}
int n, m, ans;

struct range {
    int l, d;
    bool operator<(const range& w) const { return d != w.d ? d < w.d : l < w.l; }
} rs[N * 2];

struct point {
    i64 y;
    int l, r;
    bool operator<(const point& p) const { return y < p.y; }
} ps0[N * 2], *_ps = ps0, tmp1[10000], tmp2[10000], tmp0[4];

struct block {
    point* ps;
    i64 a;
    int l, r, pp, d;
    void init(range* a, int n) {
        pp = n;
        ps = _ps, _ps += pp;
        for (int i = 0; i < n; ++i) ps[i] = (point){ 0, a[i].l, a[i].l + a[i].d };
        this->a = 0;
        d = a[0].d + 1;
        l = ps[0].l;
        r = ps[pp - 1].r;
    }
    void modify(int L, int R, i64 a) {
        i64 ad = a * d;
        if (L <= l && r <= R)
            this->a += ad;
        else if (L <= r && l <= R) {
            int p1 = 0, p2 = 0, p0 = 0;
            for (int i = 0; i < pp; ++i) {
                if (L <= ps[i].l && ps[i].r <= R) {
                    ps[i].y += ad;
                    tmp1[p1++] = ps[i];
                } else if (L > ps[i].r || R < ps[i].l)
                    tmp2[p2++] = ps[i];
                else {
                    ps[i].y += a * (std::min(R, ps[i].r) - std::max(L, ps[i].l) + 1);
                    tmp0[p0++] = ps[i];
                }
            }
            if (p0) {
                std::sort(tmp0, tmp0 + p0);
                std::merge(tmp0, tmp0 + p0, tmp2, tmp2 + p2, tmp2 + p2);
                std::merge(tmp1, tmp1 + p1, tmp2 + p2, tmp2 + p2 + p2 + p0, ps);
            } else
                std::merge(tmp1, tmp1 + p1, tmp2, tmp2 + p2, ps);
        }
    }
    void query(int L, int R, i64 a) {
        if (L <= l && r <= R)
            ans += std::upper_bound(ps, ps + pp, point{ a - this->a, 0 }) - ps;
        else if (L <= r && l <= R) {
            a -= this->a;
            for (int i = 0; i < pp; ++i)
                if (L <= ps[i].l && ps[i].r <= R && ps[i].y <= a)
                    ++ans;
        }
    }
};

struct seq {
    block* bs;
    int bp;
    void init(range* a, int n) {
        int bsz = sqrt(n * log2(n)) / 4 + 1;
        bp = (n - 1) / bsz + 1;
        bs = new block[bp];
        for (int i = 0, l = 0, r; i < bp; ++i, l = r) {
            r = std::min(n, l + bsz);
            bs[i].init(a + l, r - l);
        }
    }
    void modify(int l, int r, i64 a) {
        for (int i = 0; i < bp; ++i) bs[i].modify(l, r, a);
    }
    void query(int l, int r, i64 a) {
        for (int i = 0; i < bp; ++i) bs[i].query(l, r, a);
    }
} ss[50];

int rp = 0, sp = 0;

int main() {
    n = _(1, 100000), m = _(1, 100000);
    rs[rp++] = (range){ 1, n - 1 };
    for (int i = 0; i < rp; ++i) {
        int l = rs[i].l, r = l + rs[i].d, m = (l + r) / 2, m1 = m + 1;
        if (l < r) {
            rs[rp++] = (range){ l, m - l };
            rs[rp++] = (range){ m1, r - m1 };
        }
    }
    std::sort(rs, rs + rp);
    for (int i = 0, j = 0; i < rp; i = j) {
        int d = rs[i].d;
        for (++j; j < rp && rs[j].d == d; ++j)
            ;
        ss[sp++].init(rs + i, j - i);
    }
    while (m--) {
        int op = _(1, 2), l = _(1, n), r = _(l, n), a = _(-1000000000, 1000000000);
        switch (op) {
            case 1:
                for (int i = 0; i < sp; ++i) ss[i].modify(l, r, a);
                break;
            case 2:
                ans = 0;
                for (int i = 0; i < sp; ++i) ss[i].query(l, r, a);
                printf("%d\n", ans);
                break;
        }
    }
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 3973ms, 内存消耗: 5432K, 提交时间: 2018-08-17 22:47:55

#include<bits/stdc++.h>
typedef long long i64;
const int N=100010;
int _(int l,int r){
	int x;
	assert(scanf("%d",&x)==1&&l<=x&&x<=r);
	return x;
}
int n,m,ans;
struct range{
	int l,d;
	bool operator<(const range&w)const{
		return d!=w.d?d<w.d:l<w.l;
	}
}rs[N*2];
struct point{
	i64 y;
	int l,r;
	bool operator<(const point&p)const{return y<p.y;}
}ps0[N*2],*_ps=ps0,tmp1[10000],tmp2[10000],tmp0[4];
struct block{
	point*ps;
	i64 a;
	int l,r,pp,d;
	void init(range*a,int n){
		pp=n;
		ps=_ps,_ps+=pp;
		for(int i=0;i<n;++i)ps[i]=(point){0,a[i].l,a[i].l+a[i].d};
		this->a=0;
		d=a[0].d+1;
		l=ps[0].l;
		r=ps[pp-1].r;
	}
	void modify(int L,int R,i64 a){
		i64 ad=a*d;
		if(L<=l&&r<=R)this->a+=ad;
		else if(L<=r&&l<=R){
			int p1=0,p2=0,p0=0;
			for(int i=0;i<pp;++i){
				if(L<=ps[i].l&&ps[i].r<=R){
					ps[i].y+=ad;
					tmp1[p1++]=ps[i];
				}else if(L>ps[i].r||R<ps[i].l)tmp2[p2++]=ps[i];
				else{
					ps[i].y+=a*(std::min(R,ps[i].r)-std::max(L,ps[i].l)+1);
					tmp0[p0++]=ps[i];
				}
			}
			if(p0){
				std::sort(tmp0,tmp0+p0);
				std::merge(tmp0,tmp0+p0,tmp2,tmp2+p2,tmp2+p2);
				std::merge(tmp1,tmp1+p1,tmp2+p2,tmp2+p2+p2+p0,ps);
			}else std::merge(tmp1,tmp1+p1,tmp2,tmp2+p2,ps);
		}
	}
	void query(int L,int R,i64 a){
		if(L<=l&&r<=R)ans+=std::upper_bound(ps,ps+pp,point{a-this->a,0})-ps;
		else if(L<=r&&l<=R){
			a-=this->a;
			for(int i=0;i<pp;++i)if(L<=ps[i].l&&ps[i].r<=R&&ps[i].y<=a)++ans;
		}
	}
};
struct seq{
	block*bs;
	int bp;
	void init(range*a,int n){
		int bsz=sqrt(n*log2(n))/4+1;
		bp=(n-1)/bsz+1;
		bs=new block[bp];
		for(int i=0,l=0,r;i<bp;++i,l=r){
			r=std::min(n,l+bsz);
			bs[i].init(a+l,r-l);
		}
	}
	void modify(int l,int r,i64 a){
		for(int i=0;i<bp;++i)bs[i].modify(l,r,a);
	}
	void query(int l,int r,i64 a){
		for(int i=0;i<bp;++i)bs[i].query(l,r,a);
	}
}ss[50];
int rp=0,sp=0;
int main(){
	n=_(1,100000),m=_(1,100000);
	rs[rp++]=(range){1,n-1};
	for(int i=0;i<rp;++i){
		int l=rs[i].l,r=l+rs[i].d,m=(l+r)/2,m1=m+1;
		//printf("[%d,%d]",l,r);
		if(l<r){
			rs[rp++]=(range){l,m-l};
			rs[rp++]=(range){m1,r-m1};
		}
	}
	std::sort(rs,rs+rp);
	for(int i=0,j=0;i<rp;i=j){
		int d=rs[i].d;
		for(++j;j<rp&&rs[j].d==d;++j);
		ss[sp++].init(rs+i,j-i);
	}
	while(m--){
		int op=_(1,2),l=_(1,n),r=_(l,n),a=_(-1000000000,1000000000);
		switch(op){
			case 1:
				for(int i=0;i<sp;++i)ss[i].modify(l,r,a);
				break;
			case 2:
				ans=0;
				for(int i=0;i<sp;++i)ss[i].query(l,r,a);
				printf("%d\n",ans);
				break;
			default:
				assert(0);
		}
	}
 	return 0;
}

上一题