cogs775 山海经 线段树

链接:http://cogs.pro/cogs/problem/problem.php?pid=775

题意:维护区间最大值及其最小字典序来源。

细节巨多……多的狗死人了……

首先我们要建出一棵线段树,这棵线段树要存放以下几个东西:最长区间,起点,终点,最长前缀,前缀终点,最长后缀,后缀起点。(所以维护打了足足六十行……查询打了三十行……)

如何查询呢?最长序列无外乎三种情况:

1、全在左子树中。我们设$len[i]$为$i$节点最长序列,则此时$len[i]=len[i<<1]$;

2、全在右子树中,同理可以得出$len[i]=len[i<<1|1]$。

3、横跨两个子树。设前缀长为$pre[i]$,后缀长为$suf[i]$,那么$len[i]=suf[i<<1]+pre[i<<1|1]$。

维护时顺带按照长度第一字典序第二要求维护区间起终点即可。

查询时按照相同方法进行查询,需要注意的是,最后一次合并时左右可能并未完全更新,上传完成后还要再找一次最优解。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 using namespace std;
  6 const int maxn=100005,inf=0x3f3f3f3f;
  7 struct node
  8 {
  9     int l,r,lmax,rmax,st,en,totmax,pre,suf,sum;
 10     node()
 11     {
 12         lmax=rmax=totmax=-inf;sum=0;
 13     }
 14 }segtree[maxn<<2];
 15 #define mid ((l+r)>>1)
 16 #define lc root<<1
 17 #define rc root<<1|1
 18 #define lson lc,l,mid
 19 #define rson rc,mid+1,r
 20 void pushup(int root)
 21 {
 22     segtree[root].sum=segtree[lc].sum+segtree[rc].sum;
 23     if(segtree[lc].lmax<segtree[lc].sum+segtree[rc].lmax)
 24     {
 25         segtree[root].lmax=segtree[lc].sum+segtree[rc].lmax;
 26         segtree[root].pre=segtree[rc].pre;
 27     }
 28     else
 29     {
 30         segtree[root].lmax=segtree[lc].lmax;
 31         segtree[root].pre=segtree[lc].pre;
 32     }
 33     if(segtree[rc].rmax<segtree[rc].sum+segtree[lc].rmax)
 34     {
 35         segtree[root].rmax=segtree[rc].sum+segtree[lc].rmax;
 36         segtree[root].suf=segtree[lc].suf;
 37     }
 38     else
 39     {
 40         segtree[root].rmax=segtree[rc].rmax;
 41         segtree[root].suf=segtree[rc].suf;
 42     }
 43     if(segtree[lc].totmax<segtree[rc].totmax)
 44     {
 45         if(segtree[rc].totmax<=segtree[lc].rmax+segtree[rc].lmax)
 46         {
 47                 segtree[root].totmax=segtree[lc].rmax+segtree[rc].lmax;
 48                 segtree[root].st=segtree[lc].suf;
 49                 segtree[root].en=segtree[rc].pre;
 50         }
 51         else
 52         {
 53             segtree[root].totmax=segtree[rc].totmax;
 54             segtree[root].st=segtree[rc].st;
 55             segtree[root].en=segtree[rc].en;
 56         }
 57     }
 58     else if(segtree[lc].totmax<segtree[lc].rmax+segtree[rc].lmax)
 59     {
 60         segtree[root].totmax=segtree[lc].rmax+segtree[rc].lmax;
 61         segtree[root].st=segtree[lc].suf;
 62         segtree[root].en=segtree[rc].pre;
 63     }
 64     else if(segtree[lc].totmax==segtree[lc].rmax+segtree[rc].lmax)
 65     {
 66         segtree[root].totmax=segtree[lc].totmax;
 67         if(segtree[lc].st>segtree[lc].suf)
 68         {
 69             segtree[root].st=segtree[lc].suf;
 70             segtree[root].en=segtree[rc].pre;
 71         }
 72         else
 73         {
 74             segtree[root].st=segtree[lc].st;
 75             segtree[root].en=segtree[root].en;
 76         }
 77     }
 78     else
 79     {
 80         segtree[root].totmax=segtree[lc].totmax;
 81         segtree[root].st=segtree[lc].st;
 82         segtree[root].en=segtree[lc].en;
 83     }
 84 }
 85 void cmp(node x,node y,node &z)
 86 {
 87     z.l=x.l,z.r=y.r;z.sum=x.sum+y.sum;
 88     if(x.lmax<x.sum+y.lmax)
 89     {
 90         z.lmax=x.sum+y.lmax;
 91         z.pre=y.pre;
 92     }
 93     else z.lmax=x.lmax,z.pre=x.pre;
 94     if(y.rmax<y.sum+x.rmax)
 95     {
 96         z.rmax=y.sum+x.rmax;
 97         z.suf=x.suf;
 98     }
 99     else
100     {
101         z.rmax=y.rmax;
102         z.suf=y.suf;
103     }
104     if(x.totmax<y.totmax)
105     {
106         if(y.totmax<=x.rmax+y.lmax)
107         {
108             z.totmax=x.rmax+y.lmax;
109             z.st=x.suf;
110             z.en=y.pre;
111         }
112         else
113         {
114             z.totmax=y.totmax;
115             z.st=y.st;
116             z.en=y.en;
117         }
118     }
119     else if(x.totmax<x.rmax+y.lmax)
120     {
121         z.totmax=x.rmax+y.lmax;
122         z.st=x.suf;
123         z.en=y.pre;
124     }
125     else if(x.totmax==x.rmax+y.lmax)
126     {
127         z.totmax=x.totmax;
128         if(x.suf<x.st)z.st=x.suf,z.en=y.pre;
129         else z.st=x.st,z.en=x.en;
130     }
131     else z.totmax=x.totmax,z.st=x.st,z.en=x.en;
132 }
133 void build(int root,int l,int r)
134 {
135     segtree[root].l=l,segtree[root].r=r;
136     if(l==r)
137     {
138         int tmp;scanf("%d",&tmp);
139         segtree[root].sum=segtree[root].lmax=segtree[root].rmax=segtree[root].totmax=tmp;
140         segtree[root].st=segtree[root].en=segtree[root].pre=segtree[root].suf=l;
141         return;
142     }
143     build(lson),build(rson);
144     pushup(root);
145 }
146 #undef mid
147 void print(node t)
148 {
149     if(t.lmax>=t.rmax)
150         if(t.lmax>=t.totmax)printf("%d %d %d\n",t.l,t.pre,t.lmax);
151         else printf("%d %d %d\n",t.st,t.en,t.totmax);
152     else if(t.rmax>t.totmax)printf("%d %d %d\n",t.suf,t.r,t.rmax);
153     else printf("%d %d %d\n",t.st,t.en,t.totmax);
154 }
155 node query(int root,int l,int r)
156 {
157     if(segtree[root].l>=l&&segtree[root].r<=r)
158         return segtree[root];
159     int mid=segtree[root].l+segtree[root].r>>1;node t1,t2,t3;
160     if(l<=mid)t1=query(lc,l,r);if(r>mid)t2=query(rc,l,r);
161     t1.l=l,t1.r=mid,t2.l=mid+1,t2.r=r;
162     cmp(t1,t2,t3);return t3;
163 }
164 int n,q;
165 int haha()
166 {
167     freopen("hill.in","r",stdin);
168     freopen("hill.out","w",stdout);
169     scanf("%d%d",&n,&q);
170     build(1,1,n);
171     for(int i=1;i<=q;i++)
172     {
173         int x,y;scanf("%d%d",&x,&y);
174         node t=query(1,x,y);
175         print(t);
176     }
177 }
178 int sb=haha();
179 int main(){;}

cogs775

.

时间: 2024-10-18 04:50:13

cogs775 山海经 线段树的相关文章

COGS 775. 山海经 【线段树】

775. 山海经 [问题描述] “南山之首日鹊山.其首日招摇之山,临于西海之上,多桂,多金玉.有草焉,其状如韭而青华,其名日祝余,食之不饥……又东三百里,日堂庭之山,多棪木,多白猿,多水玉,多黄金. 又东三百八十里,日猨翼之山,其中多怪兽,水多怪鱼,多白玉,多蝮虫,多怪蛇,名怪木,不可以上.……” <山海经>是以山为纲,以海为线记载古代的河流.植物.动物及矿产等情况,而且每一条记录路线都不会有重复的山出现.某天,你的地理老师想重游<山海经>中的路线,为了简化问题,老师已经把每座山用

山海经 (线段树高阶操作)

前几天看mike的ppt发现有线段树的题,就挑了第一道题搞搞吧,然后就gg了,花了三天时间总算搞掉了 先放题: 775. 山海经 ★★★☆   输入文件:hill.in   输出文件:hill.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] “南山之首日鹊山.其首日招摇之山,临于西海之上,多桂,多金玉.有草焉,其状如韭而青华,其名日祝余,食之不饥……又东三百里,日堂庭之山,多棪木,多白猿,多水玉,多黄金. 又东三百八十里,日猨翼之山,其中多怪兽,水多怪鱼,多白玉,

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)

[BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依次更新这log位,如果最高位依然有进位,那么找到最高位后面的第一个0,将中间的所有1变成0,那个0变成1.这个显然要用到线段树,但是复杂度是nlog2n的,肯定过不去. 于是我在考场上yy了一下,这log位是连续的,我们每次都要花费log的时间去修改一个岂不是很浪费?我们可以先在线段树上找到这段区间

bzoj1798: [Ahoi2009]Seq 维护序列seq 线段树

题目传送门 这道题就是线段树 先传乘法标记再传加法 #include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int M=400010; LL read(){ LL ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}

Vijos P1066 弱弱的战壕【多解,线段树,暴力,树状数组】

弱弱的战壕 描述 永恒和mx正在玩一个即时战略游戏,名字嘛~~~~~~恕本人记性不好,忘了-_-b. mx在他的基地附近建立了n个战壕,每个战壕都是一个独立的作战单位,射程可以达到无限(“mx不赢定了?!?”永恒[email protected][email protected]). 但是,战壕有一个弱点,就是只能攻击它的左下方,说白了就是横纵坐标都不大于它的点(mx:“我的战壕为什么这么菜”ToT).这样,永恒就可以从别的地方进攻摧毁战壕,从而消灭mx的部队. 战壕都有一个保护范围,同它的攻击

luogu 1712 区间(线段树+尺取法)

题意:给出n个区间,求选择一些区间,使得一个点被覆盖的次数超过m次,最小的花费.花费指的是选择的区间中最大长度减去最小长度. 坐标值这么大,n比较小,显然需要离散化,需要一个技巧,把区间转化为半开半闭区间,然后线段树的每一个节点表示一个半开半闭区间. 接着我们注意到需要求最小的花费,且这个花费只与选择的区间集合中的最大长度和最小长度有关. 这意味着如果最大长度和最小长度一定,我们显然是需要把中间长度的区间尽量的选择进去使答案不会变的更劣. 不妨把区间按长度排序,枚举每个最小长度区间,然后最大区间

【BZOJ】1382: [Baltic2001]Mars Maps (线段树+扫描线)

1382: [Baltic2001]Mars Maps Time Limit: 5 Sec  Memory Limit: 64 MB Description 给出N个矩形,N<=10000.其坐标不超过10^9.求其面积并 Input 先给出一个数字N,代表有N个矩形. 接下来N行,每行四个数,代表矩形的坐标. Output 输出面积并 Sample Input 2 10 10 20 20 15 15 25 30 Sample Output 225 本以为是傻逼题,没想到不容易啊- 线段树+扫描

BZOJ 1012: [JSOI2008]最大数maxnumber(线段树)

012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MB Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插入操作.语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列