[Noi2016十连测第三场]线段树

  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 }
View Code

题目大意:线段树

【问题描述】
小𝐷写完了随机哈夫曼树,凭信仰开始补觉,想起了在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,倍增能加速这个过程。

可持久化线段树+线段树+倍增。

posted @ 2016-06-20 22:00  oyzx~  阅读(614)  评论(0编辑  收藏  举报