CSU 2151 集训难度【多标记线段树】

http://acm.csu.edu.cn/csuoj/problemset/problem?pid=2151

Input

第一行三个数n,m,v0 表示有n名萌新和m次调整,初始时全部萌新的集训难度都为v0

第2~m+1行 每行三个数或四个数

0 x y v 表示把 [x,y]区间内的萌新的集训难度都增加v

1 x y v 表示把 [x,y]区间内的萌新的集训难度都变为v

2 x y表示询问[x,y]区间内萌新的集训难度之和

0<n,m<=10^5, |v|<=10^5

Output

每个询问一行,输出答案

Sample Input

3 5 0
0 1 3 1
1 2 3 2
2 1 1  
2 2 2
2 2 3

Sample Output

1
2
4

 

多标记线段树处理法(洛谷3373,codevs4927)

 

#include<cstdio>
#include<string>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<cstring>
#include<set>
#include<queue>
#include<algorithm>
#include<vector>
#include<map>
#include<cctype>
#include<stack>
#include<sstream>
#include<list>
#include<assert.h>
#include<bitset>
#include<numeric>
#define debug() puts("++++")
#define gcd(a,b) __gcd(a,b)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a,b,sizeof(a))
#define sz size()
#define be begin()
#define pu push_up
#define pd push_down
#define cl clear()
#define mdzz int mid=(l+r)>>1;
#define lowbit(x) -x&x
#define all 1,n,1
#define rep(i,x,n) for(int i=(x); i<(n); i++)
#define in freopen("in.in","r",stdin)
#define out freopen("out.out","w",stdout)
using namespace std;
typedef long long ll;
typedef unsigned long long ULL;
typedef pair<int,int> P;
const int INF = 0x3f3f3f3f;
const ll LNF = 1e18;
const int maxn = 200010 + 20;
const int maxm = 1e6 + 10;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int dx[] = {-1,1,0,0,1,1,-1,-1};
const int dy[] = {0,0,1,-1,1,-1,1,-1};
int dir[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int n,m;
int x,y,op;
ll a[maxn];
ll sum[maxn<<2],add[maxn<<2],cover[maxn<<2],z,v;
void pushup(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1]; //区间查询和
}
void pushdown(int rt,int m)
{
    if(cover[rt])
    {
        //区间覆盖
        cover[rt<<1] = cover[rt<<1|1] = cover[rt];
        sum[rt<<1] = cover[rt]*(m-(m>>1));
        sum[rt<<1|1] = cover[rt]*(m>>1);
        add[rt<<1] = add[rt<<1|1] =  0;     //set操作中取消add
        cover[rt] = 0;
    }
    if(add[rt])
    {
        //区间求和
        add[rt<<1]   += add[rt];
        add[rt<<1|1] += add[rt];
        sum[rt<<1] += add[rt]*(m-(m>>1));
        sum[rt<<1|1] += add[rt]*(m>>1);
        add[rt]=0;
    }
}
void build(int l,int r,int rt)
{
    add[rt]=cover[rt]=0;
    if(l==r)
    {
        sum[rt]=v;
        return;
    }
    mdzz
    build(lson);
    build(rson);
    pushup(rt);
}
void update(int op,int L,int R,int c,int l,int r,int rt)
{
    if(L<=l && R>=r)
    {
        if(op==0) //add
        {
            add[rt] += c;
            sum[rt] += (ll)c*(r-l+1);
        }
        else
        {
            cover[rt] = c;
            add[rt] = 0; //
            sum[rt] = (ll)c*(r-l+1);
        }
        return ;
    }
    pushdown(rt,r-l+1);
    mdzz
    if(L<=mid) update(op,L,R,c,lson);
    if(R>mid)  update(op,L,R,c,rson);
    pushup(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&R>=r) return sum[rt];
    pushdown(rt,r-l+1);
    mdzz
    ll res=0;
    if(L<=mid) res += query(L,R,lson);
    if(R>mid) res += query(L,R,rson);
    return res;
}

int main()
{
    while(~scanf("%d%d%lld",&n,&m,&v))
    {
        build(1,n,1);
        while(m--)
        {
            scanf("%d",&op);
            if(op==2)
            {
                scanf("%d%d",&x,&y);
                printf("%lld\n",query(x,y,1,n,1));
            }
            else
            {
                scanf("%d%d%lld",&x,&y,&z);
                update(op,x,y,z,1,n,1);
            }
        }
    }
}
多次区间更新操作——>多个lazy

 

posted @ 2018-08-18 14:36  Roni_i  阅读(146)  评论(0编辑  收藏  举报