HDU 4747 线段树 区间更新
来源:互联网 发布:男士内裤淘宝店铺名 编辑:程序博客网 时间:2024/06/08 11:10
线段树 区间更新
题意:
给出一个数列,现在定义一个function,数列的某一个区间
里从0开始没有出现的最小值就是f(i,j) 的值。[i,j] 现在请求出该数列所有子区间的函数值。
思路:
首先太菜,看题,看数据、看意思、分析函数,但是也没有看出这是一个可以用线段树解决的问题。比较菜。分析数据200000的数据量,其子区间会很多,暴力解决必定超时,而在分析函数,每次如果只求出
也就是每次删除最开始的一个数,然后求出区间和的话,只需更新函数的值即可 。f函数值是递增的,可以手动分析一下,如果删除最前面的一个数字比如删除了a[1] ,那么受影响的是f(1,i) > a[i] 而a[i] 的下一次出现的位置便不受影响。所以区间更新即可。[1,i],[1,i+1],⋅⋅⋅[1,n]或者[2,i],[2,i+1],⋅⋅⋅[2,n]
#include <iostream>#include <cstdio>#include <cstring>#include <map>using namespace std;const int maxn = 200005;int n,a[maxn],Next[maxn],mex[maxn];map<int,int>mp;struct Node{ int l,r; long long sum; int mx; int lazy;}rt[maxn*3];void Update_same(int i,int v) /*lazy的妙用*/{ rt[i].sum = (long long)v*(rt[i].r - rt[i].l + 1); rt[i].mx = v; rt[i].lazy = true;}void Push_up(int i) /*向上更新mx和sum*/{ if(rt[i].l == rt[i].r ) return ; rt[i].sum = rt[i<<1].sum + rt[(i<<1)|1].sum; rt[i].mx = max(rt[i<<1].mx,rt[(i<<1)|1].mx);}void push_down(int i) /*向下更新,lazy的使用可以减少很多不必要的运算*/{ if(rt[i].l == rt[i].r ) return ; if(rt[i].lazy) { Update_same(i<<1,rt[i].mx); Update_same((i<<1)|1,rt[i].mx); rt[i].lazy = 0; }}void build(int i,int l,int r) /*建树*/{ rt[i].l = l; rt[i].r = r; rt[i].lazy = 0; if(l == r) { rt[i].sum = mex[l]; rt[i].mx = mex[l]; return ; } int mid = (l + r) >> 1; build(i<<1,l,mid); build((i<<1)|1,mid+1,r); Push_up(i);}void Update(int i,int l,int r,int v) /*区间更新,可以当模板*/{ if(rt[i].l == l && rt[i].r == r) { Update_same(i,v); return ; } push_down(i); int mid = (rt[i].l + rt[i].r)>>1; if(mid >= r) Update(i<<1,l,r,v); else if(l > mid) { Update((i<<1)|1,l,r,v); } else { Update(i<<1,l,mid,v); Update((i<<1)|1,mid+1,r,v); } Push_up(i);}int Get(int i,int v) /*返回mx > v 的区间位置*/{ if(rt[i].l == rt[i].r) return rt[i].l; push_down(i); if(rt[i<<1].mx > v) return Get(i<<1,v); else return Get((i<<1)|1,v);}int main(int argc, char const *argv[]){ //freopen("in.txt","r",stdin); while(scanf("%d",&n) != EOF && n) { for(int i = 1;i <= n; i++) scanf("%d",&a[i]); mp.clear(); int temp = 0; for(int i = 1;i <= n; i++) { mp[a[i]] = 1; while(mp.find(temp) != mp.end()) temp++; mex[i] = temp; } mp.clear(); for(int i = n;i >= 1; i--) { if(mp.find(a[i]) == mp.end()) Next[i] = n + 1; else Next[i] = mp[a[i]]; mp[a[i]] = i; } build(1,1,n); long long ans = 0; for(int i = 1;i <= n; i++) { ans += rt[1].sum; if(rt[1].mx > a[i]) { int l = Get(1,a[i]); int r = Next[i]; if(r > l) { Update(1,l,r-1,a[i]); } } Update(1,i,i,0); } printf("%I64d\n",ans); } return 0;}
阅读全文
0 0
- HDU 4747 线段树 + 区间更新 + java
- HDU 4747 线段树 区间更新
- hdu 4747 Mex(线段树区间更新+二分)
- HDU 1698 区间更新线段树
- hdu 3308 线段树 区间更新 LICS
- HDU 3308 LCIS 线段树区间更新
- hdu 4578 Transformation [线段树 区间更新]
- hdu 1698 线段树区间更新
- hdu 3308 线段树区间更新
- hdu 2795 线段树,区间更新求补值
- HDU 1698 【线段树区间更新】
- HDU 1698(线段树区间更新)
- hdu 1698 线段树 区间更新
- HDU 1698 线段树区间更新模板
- HDU 1698(线段树 区间更新)
- HDU 4578(线段树区间更新)
- hdu 1698 线段树 区间更新
- HDU 4893(线段树区间更新)
- MyBatis-SQL映射文件-总结
- 读Zepto源码之Event模块
- js中内存(栈 堆)
- 数组分段和最大值最小问题
- Android 关于arm64-v8a、armeabi-v7a、armeabi、x86下的so文件兼容问题
- HDU 4747 线段树 区间更新
- 怎么判断软件公司是否靠谱
- 工作小记录,server中调用update却被回滚。
- 【RabbitMQ】—— Exchange类型
- 手写选择题识别-封装tensorflow模型-移植到android程序
- 将其他编码文件转化为UTF8文件
- html css伪元素标签(二)灵活
- ES6数组扩展
- Gradle2.0用户指南翻译——第二章. 概述