标签:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 using namespace std; 7 #define maxn 100005 8 #define maxk 4000005 9 int n,m,q,tot,t1,t2,ans,L[maxn][18],R[maxn][18]; 10 void read(int &x){ 11 x=0; int f=1; char ch; 12 for (ch=getchar();!isdigit(ch);ch=getchar()) if (ch==‘-‘) f=-1; 13 for (;isdigit(ch);ch=getchar()) x=x*10+ch-‘0‘; x*=f; 14 } 15 struct Seg{ 16 int sm; 17 }tree1[maxk]; 18 struct mess{ 19 int l,r; 20 }chg[maxn]; 21 struct Segment{ 22 void maketree(int k,int l,int r){ 23 if (l==r){ 24 read(tree1[k].sm); 25 return; 26 }int mid=(l+r)>>1; 27 maketree(k<<1,l,mid),maketree(k<<1|1,mid+1,r); 28 tree1[k].sm=max(tree1[k<<1].sm,tree1[k<<1|1].sm); 29 } 30 void change(int k,int l,int r,int x,int y){ 31 if (l==r&&r==x){ 32 tree1[k].sm=y; 33 return; 34 }int mid=(l+r)>>1; 35 if (x<=mid) change(k*2,l,mid,x,y); 36 else change(k<<1|1,mid+1,r,x,y); 37 tree1[k].sm=max(tree1[k<<1].sm,tree1[k<<1|1].sm); 38 } 39 void query(int k,int l,int r,int x,int y){ 40 if (l>=x&&r<=y){ 41 ans=max(ans,tree1[k].sm); 42 return; 43 } int mid=(l+r)>>1; 44 if (x<=mid) query(k<<1,l,mid,x,y); 45 if (y>mid) query(k<<1|1,mid+1,r,x,y); 46 } 47 }Tree1; 48 struct SEg{ 49 int cover; 50 }tree2[maxk]; 51 int root[maxn],son[maxk][2]; 52 struct SEgment{ 53 void insert(int p,int &k,int l,int r,int x,int y,int z){ 54 k=++tot,tree2[k]=tree2[p]; son[k][0]=son[p][0],son[k][1]=son[p][1]; 55 if (l>=x&&r<=y){ 56 tree2[k].cover=z; 57 return; 58 }int mid=(l+r)/2; 59 if (x<=mid) insert(son[p][0],son[k][0],l,mid,x,y,z); 60 if (y>mid) insert(son[p][1],son[k][1],mid+1,r,x,y,z); 61 } 62 void query(int k,int l,int r,int x){ 63 t1=max(t1,tree2[k].cover); 64 if (l==r) return; 65 int mid=(l+r)>>1; 66 if (x<=mid) query(son[k][0],l,mid,x); 67 else query(son[k][1],mid+1,r,x); 68 } 69 }Tree2; 70 struct Fseg{ 71 int cover; 72 }tree3[maxk]; 73 struct Fsegment{ 74 void insert(int k,int l,int r,int x,int y,int z){ 75 if (l>=x&&r<=y){ 76 tree3[k].cover=z; 77 return; 78 }int mid=(l+r)>>1; 79 if (x<=mid) insert(k<<1,l,mid,x,y,z); 80 if (y>mid) insert(k<<1|1,mid+1,r,x,y,z); 81 } 82 void query(int k,int l,int r,int x){ 83 t1=max(t1,tree3[k].cover); 84 if (l==r) return; 85 int mid=(l+r)>>1; 86 if (x<=mid) query(k<<1,l,mid,x); 87 else query(k<<1|1,mid+1,r,x); 88 } 89 }Tree3; 90 int main(){ 91 read(n),read(m),read(q); 92 Tree1.maketree(1,1,n); 93 tot=0,memset(root,0,sizeof(root)); 94 memset(L,0,sizeof(L)); 95 memset(R,0,sizeof(R)); 96 for (int i=1;i<=m;i++) read(chg[i].l),read(chg[i].r); 97 for (int i=1;i<=m;i++) Tree2.insert(root[i-1],root[i],1,n,chg[i].l,chg[i].r,i); 98 for (int i=1;i<=m;i++){ 99 t1=0; Tree3.query(1,1,n,chg[i].l); L[i][0]=t1; 100 t1=0; Tree3.query(1,1,n,chg[i].r); R[i][0]=t1; 101 Tree3.insert(1,1,n,chg[i].l,chg[i].r,i); 102 } 103 for (int i=1;i<=17;i++){ 104 for (int j=1;j<=m;j++){ 105 L[j][i]=L[L[j][i-1]][i-1]; 106 R[j][i]=R[R[j][i-1]][i-1]; 107 } 108 } 109 for (int type,l,r,w,i=1;i<=q;i++){ 110 read(type),read(l),read(r); 111 if (type==1) Tree1.change(1,1,n,l,r); 112 else{ 113 read(w); 114 t1=0; Tree2.query(root[r],1,n,w); t2=t1; 115 if (t1>=l){ 116 for (int j=17;j>=0;j--) if (L[t1][j]&&L[t1][j]>=l) t1=L[t1][j]; 117 for (int j=17;j>=0;j--) if (R[t2][j]&&R[t2][j]>=l) t2=R[t2][j]; 118 ans=0,t1=chg[t1].l,t2=chg[t2].r,Tree1.query(1,1,n,t1,t2); 119 }else ans=0,Tree1.query(1,1,n,w,w); 120 printf("%d\n",ans); 121 } 122 } 123 return 0; 124 }
题目大意:线段树
【问题描述】
小??写完了随机哈夫曼树,凭信仰开始补觉,想起了在ZJOI见过的一
个模型:
? 给出一个长度为??的数组??,1 ∼ ??标号。
? ??个操作,每个操作有两个参数????, ????,表示将区间[????, ????]中的所有数修
改为这个区间的最大值。
这个问题可以简单地用线段树来完成,现在小??将这个问题扩展了一
下。
给出一个长度为??的初始数组??,以及??个操作,需要维护:
? 求依次进行编号为[??,??]的这一段操作后????的值。这些询问互相独立,
即可以理解为“假如进行这一段操作后,????的值会变成多少”。
? 将????的值修改为??,即修改初始数组,这次修改会影响它之后的所有
询问。
可以参考输入格式来帮助理解题意。
【输入格式】
从文件segment.in中读入数据。
第一行,三个正整数??, ??, ??,表示数组长度,操作数和询问数。
第二行,??个正整数????。
第5页共10 页
NOI2016模拟赛2016 年6 月线段树
接下来??行,每行两个正整数????, ????,描述一个操作。
接下来??行,每行描述一次询问或一次初始数组的修改,格式如下:
? 1 ?? ??,将????的值修改为??。
? 2 ?? ?? ??,询问假如进行编号为[??,??]的这一段操作后????的值。
【输出格式】
输出到文件segment.out中。
对于每次询问输出一行一个正整数,表示“假如进行编号为[??,??]的这
一段操作后????的值”。
【样例输入】
5 3 6
5 3 1 4 2
2 3
3 4
1 5
2 1 2 3
1 4 5
2 1 2 3
1 4 4
1 1 4
2 1 3 1
【样例输出】
4
5
4
【数据规模】
对于10%的数据,??, ??, ?? ≤ 100。
对于30%的数据,??, ??, ?? ≤ 10000。
对于另20%的数据,询问时?? = 1。
对于80%的数据,??, ??, ?? ≤ 50000(包含前一档?? = 1)。
对于100%的数据,??, ??, ?? ≤ 105,1 ≤ ????, ?? ≤ 105。
做法:当时一直想写正解,花了不少时间,最后只剩下了10分暴力(雾——)
这题正解是可持久化线段树+普通线段树+倍增,这题有一个很重要的性质,对于每个询问我们可以转化为询问一段区间的最值。
首先,每个修改操作是已知的,我们对这些操作建立可持久化线段树,预处理fa1,fa2值,分别表示之前能覆盖该操作左,右端点的出现最晚的修改操作是哪个,为什么要可持久化呢,因为我们需要询问历史版本啊!! 对于后面的q个操作,如果是修改操作,我们直接在普通线段树上修改即可。如果是询问操作,我们在可持久化线段树上找到在R之前,最晚出现的能覆盖这个点的修改操作,此时我们通过fa1,fa2,找到最广的区间,这两个区间必须大于等于l,倍增能加速这个过程。
可持久化线段树+线段树+倍增。
标签:
原文地址:http://www.cnblogs.com/OYzx/p/5601983.html