玲珑oj 1117 线段树+离线+离散化,laz大法
Posted zzq
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了玲珑oj 1117 线段树+离线+离散化,laz大法相关的知识,希望对你有一定的参考价值。
1117 - RE:从零开始的异世界生活
Time Limit:1s Memory Limit:256MByte
Submissions:438Solved:68
DESCRIPTION
486到了异世界,看到了一群可爱的妹子比如蕾姆啊,艾米莉亚啊,拉姆啊,白鲸啊,怠惰啊等等!
有一天膜女告诉486说她的能力可能不能再用了,因为膜女在思考一个数据结构题,没心情管486了。
486说我来帮你做,膜女说你很棒棒哦!
给一个集合,最开始为空(不是数学上的集合)
五个操作:
1、插入x
2、把小于x的数变成x
3、把大于x的数变成x
4、求集合中第x小数
5、求集合中小于x的数个数
INPUT
第一行一个数m
后面有m行,每行格式为opt x,opt表示是什么操作,x表示操作的值
OUTPUT
对于每个4,5操作,输出一个值表示答案
SAMPLE INPUT
5
1 1
1 3
4 1
2 33
4 1
SAMPLE OUTPUT
1
33
HINT
m <= 100000 , x <= 1000000000
SOLUTION
这个题目是暑假前玲珑的一次我参加的比赛,很遗憾当时还很弱不会ST直接放弃了,现在又回来看见,当时看别人博客题解是什么值域线段树,好吧我也不会,
copy一个代码跑了960+ms险过感觉怎么这么慢捏,再次看题目感觉就是普通线段树就可做。
虽然n<1e9,但m最大10w,最多也就10w个不同的x,我想到用map离散化处理一下,为了方便询问我是从2开始的,由于要对所有的x离散化,所以必须先离散化结束才能应对所有的询问,这里采用了离线的作法,先保存询问值,预处理完在依次模拟询问的过程。
没有很奇葩的询问,单点更新,区间修改和二分查找,注意细节的话就好了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define inf 0x3f3f3f3f 4 #define LL long long 5 #define MAX 100005 6 map<int,int>M1; 7 int N,x[MAX]={2147483647},P[MAX]; 8 struct Ask 9 { 10 int opt,x; 11 }a[MAX]; 12 struct SegTree 13 { 14 #define M ((L+R)>>1) 15 #define lc (id<<1) 16 #define rc (id<<1|1) 17 int sum[MAX<<2],laz[MAX<<2];//laz[i]表示全部变为i 18 void init() 19 { 20 memset(sum,0,sizeof(sum)); 21 memset(laz,-1,sizeof(laz)); 22 } 23 void pushup(int L,int R,int id) 24 { 25 sum[id]=sum[lc]+sum[rc]; 26 } 27 void pushdown(int L,int R,int id) 28 { 29 if(laz[id]!=-1){ 30 sum[lc]=sum[rc]=0; 31 laz[lc]=laz[rc]=0; 32 laz[id]=-1; 33 } 34 } 35 void irt(int L,int R,int id,int x,int v) 36 { 37 if(L==R){ 38 sum[id]+=v; 39 return; 40 } 41 pushdown(L,R,id); 42 if(x<=M) irt(L,M,lc,x,v); 43 else irt(M+1,R,rc,x,v); 44 pushup(L,R,id); 45 } 46 int change(int L,int R,int id,int l,int r) 47 { 48 if(L>=l&&R<=r){ 49 int res=sum[id]; 50 sum[id]=0; 51 laz[id]=0; 52 return res; 53 } 54 pushdown(L,R,id); 55 int res=0; 56 if(l<=M) res+=change(L,M,lc,l,r); 57 if(r>M) res+=change(M+1,R,rc,l,r); 58 pushup(L,R,id); 59 return res; 60 } 61 int ask1(int L,int R,int id,int x) 62 { 63 if(L==R) return P[L]; 64 pushdown(L,R,id); 65 if(sum[lc]>=x){ 66 return ask1(L,M,lc,x); 67 } 68 else{ 69 return ask1(M+1,R,rc,x-sum[lc]); 70 } 71 } 72 int ask2(int L,int R,int id,int x) 73 { 74 if(L==R) return sum[id]; 75 pushdown(L,R,id); 76 if(x<=M) return ask2(L,M,lc,x); 77 else if (x>M) return sum[lc]+ask2(M+1,R,rc,x); 78 } 79 80 }seg; 81 int main() 82 { 83 //freopen("in.txt","r",stdin); 84 int n,m,i,j,k; 85 scanf("%d",&n); N=1; 86 for(i=1;i<=n;++i) 87 { 88 scanf("%d%d",&a[i].opt,&a[i].x); 89 x[i]=a[i].x; 90 } 91 sort(x+1,x+n+1); 92 for(i=1;i<=n;++i) 93 { 94 if(x[i]==x[i-1]) continue; 95 M1[x[i]]=++N; 96 P[N]=x[i]; 97 } 98 N++; 99 seg.init(); 100 for(i=1;i<=n;++i) 101 { 102 int x1=M1[a[i].x]; 103 if(a[i].opt==1){ 104 seg.irt(1,N,1,x1,1); 105 } 106 else if(a[i].opt==2){ 107 seg.irt(1,N,1,x1,seg.change(1,N,1,1,x1-1)); 108 } 109 else if(a[i].opt==3){ 110 seg.irt(1,N,1,x1,seg.change(1,N,1,x1+1,N)); 111 } 112 else if(a[i].opt==4){ 113 printf("%d\n",seg.ask1(1,N,1,a[i].x)); 114 } 115 else if(a[i].opt==5){ 116 printf("%d\n",seg.ask2(1,N,1,x1-1)); 117 } 118 } 119 return 0; 120 }
以上是关于玲珑oj 1117 线段树+离线+离散化,laz大法的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces817 F. MEX Queries(线段树,01序列同时维护翻转laz和覆盖laz)
CCPC河南省赛B-树上逆序对| 离线处理|树状数组 + 线段树维护逆序对 + dfs序 + 离散化
LightOJ 1089 - Points in Segments (II) 线段树区间修改+离散化