BZOJ_4636_蒟蒻的数列_线段树+动态开点

Description

蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列

题目描述

DCrusher有一个数列,初始值均为0,他进行N次操作,每次将数列[a,b)这个区间中所有比k小的数改为k,他想知

道N次操作后数列中所有元素的和。他还要玩其他游戏,所以这个问题留给你解决。

Input

第一行一个整数N,然后有N行,每行三个正整数a、b、k。

N<=40000 , a、b、k<=10^9

Output

一个数,数列中所有元素的和

Sample Input

4
2 5 1
9 10 4
6 8 2
4 6 3

Sample Output

16


把操作离线并从小到大排序,相当于线段树维护区间赋值操作。

本题可以离散化也可以动态开点,我这里处理不好线段树维护离散后的区间因此写了动态开点。

注意pushdown操作时如果没有这个儿子也要开出来。

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stdlib.h>
using namespace std;
#define N 40050
#define maxn 1000000000
typedef long long ll;
struct A {
    int l,r,k;
}a[N];
bool cmp(const A &x,const A &y) {return x.k<y.k;}
int tag[N*80],cnt,n,ls[N*80],rs[N*80];
ll t[N*80];
/*int make(int x) {
    return lower_bound(v+1,v+cnt+1,x)-v;
}*/
void pushdown(int l,int r,int &p,int w) {
    if(!p) p=++cnt;
    t[p]=1ll*w*(r-l+1); tag[p]=w;
}
void update(int l,int r,int x,int y,int w,int &p) {
    if(p==0) p=++cnt;
    if(x<=l&&y>=r) {
        t[p]=1ll*w*(r-l+1);
        tag[p]=w;
        return ;
    }
    int mid=(l+r)>>1;
    if(tag[p]) {
        pushdown(l,mid,ls[p],tag[p]);
        pushdown(mid+1,r,rs[p],tag[p]);
        tag[p]=0;
    }
    if(x<=mid) update(l,mid,x,y,w,ls[p]);
    if(y>mid) update(mid+1,r,x,y,w,rs[p]);
    t[p]=t[ls[p]]+t[rs[p]];
}
int main() {
    scanf("%d",&n);
    int i;
    for(i=1;i<=n;i++) {
        scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].k);
        a[i].r--;
        /*v[++cnt]=a[i].l;
        v[++cnt]=a[i].r;*/
    }
    /*sort(v+1,v+cnt+1);
    cnt=unique(v+1,v+cnt+1)-v-1;
    printf("%d\n",cnt);
    for(i=1;i<=cnt;i++) printf("%d\n",v[i]); */
    sort(a+1,a+n+1,cmp);
    int root=0;
    for(i=1;i<=n;i++) {
        if(a[i].k==0) continue;
        /*printf("%d %d\n",make(a[i].l),make(a[i].r));
        update(1,cnt,make(a[i].l),make(a[i].r),a[i].k,1);
        printf("sum=%lld\n",t[1]);*/
        update(1,maxn,a[i].l,a[i].r,a[i].k,root);
    }
    printf("%lld\n",t[1]);
}

原文地址:https://www.cnblogs.com/suika/p/9062675.html

时间: 2024-08-12 05:44:49

BZOJ_4636_蒟蒻的数列_线段树+动态开点的相关文章

[bzoj4636]蒟蒻的数列_线段树

蒟蒻的数列 bzoj-4636 题目大意:给定一个序列,初始均为0.n次操作:每次讲一段区间中小于k的数都变成k.操作的最后询问全局和. 注释:$1\le n\le 4\cdot 10^4$. 想法:那个操作就是一个不好好说话的操作,说白了就是对区间的每一个数取max 然后我们对于那个序列建立分治线段树.每个操作我都把它挂在对应的log的点上. n个操作都执行完了之后我们从1号节点深搜,更新答案即可. 最后,附上丑陋的代码... ... #include <iostream> #include

hdu 6183 Color it (线段树 动态开点)

Do you like painting? Little D doesn't like painting, especially messy color paintings. Now Little B is painting. To prevent him from drawing messy painting, Little D asks you to write a program to maintain following operations. The specific format o

HDU6183 Color it (线段树动态开点)

题意: 一个1e6*1e6的棋盘,有两个操作:给(x,y)加上颜色c,或查找(1,y1)到(x,y2)内的颜色种类数量,最多有50种颜色 思路: 建立50颗线段树,对每个颜色的线段树,维护每个y坐标上x的最小值 但是这样会爆内存,于是动态开点即可 动态开点之后T了一发,就改了下查询的函数,只要有满足在矩形的该颜色,就全线return,果然快了好多 代码: #include<iostream> #include<cstdio> #include<algorithm> #i

线段树动态开点

//zz https://blog.csdn.net/u012972031/article/details/88751811//https://www.luogu.org/problemnew/show/P3372 #include<cstdio> #include<iostream> using namespace std; const int N=300010; struct node{ int ls,rs,lazy; long long sum; }tr[N]; int ro

线段树动态开点之逆序对

对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对.求这段正整数序列中逆序对的数目.Input第一行,一个数n,表示序列中有n个数.N<=5*10^5第二行n个数,表示给定的序列.序列中每个数字不超过10^9Output给定序列中逆序对的数目.Sample Input65 4 2 6 3 1Sample Output11 #include<cstdio> #define ll long long using namespace std; const int

【BZOJ-4636】蒟蒻的数列 动态开点线段树 ||(离散化) + 标记永久化

4636: 蒟蒻的数列 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 247  Solved: 113[Submit][Status][Discuss] Description 蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列 题目描述 DCrusher有一个数列,初始值均为0,他进行N次操作,每次将数列[a,b)这个区间中所有比k小的数改为k,他想知 道N次操作后数列中所有元素的和.他还要玩其他游戏,所以这个问题留给你解决. Input 第一

bzoj 4636: 蒟蒻的数列

4636: 蒟蒻的数列 Description 蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列 题目描述 DCrusher有一个数列,初始值均为0,他进行N次操作,每次将数列[a,b)这个区间中所有比k小的数改为k,他想知 道N次操作后数列中所有元素的和.他还要玩其他游戏,所以这个问题留给你解决. Input 第一行一个整数N,然后有N行,每行三个正整数a.b.k. N<=40000 , a.b.k<=10^9 Output 一个数,数列中所有元素的和 Sample Input 4 2 5

【BZOJ】4636: 蒟蒻的数列

4636: 蒟蒻的数列 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 145  Solved: 71[Submit][Status][Discuss] Description 蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列 题目描述 DCrusher有一个数列,初始值均为0,他进行N次操作,每次将数列[a,b)这个区间中所有比k小的数改为k,他想知 道N次操作后数列中所有元素的和.他还要玩其他游戏,所以这个问题留给你解决. Input 第一行

bzoj1789 AHOI 维护数列(线段树)

首先想到线段树,然后刚开始写忽然想到树状数组求和岂不是更快,而且编程复杂度又小,于是把之前写的删掉,写树状数组,写完模版之后忽然发现这题竟然是区间修改! 于是又删掉重写,忽然发现不会处理又加又乘的,果断看题解-- 经过几乎两个小时的调试,终于1A. 需要注意的是,一定要让线段树的每一个区间保存的值时刻为正确的,这样才能在调用时直接返回.比如说这道题的change和query操作的最后一句话: sum:=f(g[k<<1]+g[k<<1+1]) 而不是 sum:=f(t[k<&