线段树模板(区间最小值优化 版) (RMQ with Shifts)

题意:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fstream>
using namespace std;
const int maxn =100010;
int RMQ[maxn<<2];
int str[maxn];
int N,M;
char ctr[35];
int total[35],cnt;

int build(int first,int second,int root)
{//建树(初始化)
    if(first==second)
    {
        RMQ[root]=str[first];
        str[first]=root;//记录原数组在线段树中的位置
        return RMQ[root];
    }
    if(first<second)
    {
        int L=root*2;
        return RMQ[root]=min(build(first,(first+second)/2,L),build((first+second)/2+1,second,L+1));
    }
    return 10000000;
}

void updata(int x,int data)
{//更新节点
    RMQ[x]=data;
    int n=x/2;
    int key;
    while(n)
    {
        RMQ[n]=min(RMQ[n*2],RMQ[n*2+1]);
        n=n/2;
    }
}

int query(int a,int b,int root,int l,int r)
{//查询 [l,r]是要查询的区间,[a,b]是root维护的区间
    if(a>r || b<l)
        return 10000000;
    if(l<=a && b<=r)
        return RMQ[root];
    else
    {
        int Left=(a+b)/2;
        if(Left>=r)
            return query(a,Left,root*2,l,r);
        if(Left<l)
            return query(Left+1,b,root*2+1,l,r);
        return min(query(a,Left,root*2,l,r),query(Left+1,b,root*2+1,l,r));
    }
    return 1000000;
}

void solve()
{
    int len=strlen(ctr);
    cnt=0;
    memset(total,0,sizeof(total));
    for(int i=6; i<len; i++)
    {
        if(ctr[i]==')')
            break;
        if(ctr[i]==',')
        {
            cnt++;
            continue;
        }
        int t=ctr[i]-'0';
        total[cnt]=t+total[cnt]*10;
    }
    if(ctr[0]=='q')
         printf("%d\n",query(1,N,1,total[0],total[1]));
    else
    {
        int key=RMQ[str[total[0]]];
        for(int i=cnt; i>=0; i--)
        {
            int z=str[total[i]];
            int q=RMQ[z];
            updata(z,key);
            key=q;
        }
    }
}

int main()
{
    scanf("%d%d",&N,&M);
    for(int i=1; i<=N; i++)
        scanf("%d",&str[i]);
    build(1,N,1);
    for(int i=0; i<M; i++)
    {
        scanf("%s",ctr);
        solve();
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-07 14:56:26

线段树模板(区间最小值优化 版) (RMQ with Shifts)的相关文章

[线段树模板] 区间修改 区间查询(详注)

输入 每个测试点(输入文件)有且仅有一组测试数据. 每组测试数据的第1行为一个整数N,意义如前文所述. 每组测试数据的第2行为N个整数,分别描述每种商品的重量,其中第i个整数表示标号为i的商品的重量Pi. 每组测试数据的第3行为一个整数Q,表示小Hi进行的操作数. 每组测试数据的第N+4~N+Q+3行,每行分别描述一次操作,每行的开头均为一个属于0或1的数字,分别表示该行描述一个询问和一次商品的价格的更改两种情况.对于第N+i+3行,如果该行描述一个询问,则接下来为两个整数Li, Ri,表示小H

ZOJ 3632 Watermelon Full of Water(dp+线段树或单调队列优化)

Watermelon Full of Water Time Limit: 3 Seconds      Memory Limit: 65536 KB Watermelon is very popular in the hot summer. Students in ZJU-ICPC Team also love watermelon very much and they hope that they can have watermelon to eat every day during the

【线段树求区间第一个不大于val的值】Lpl and Energy-saving Lamps

https://nanti.jisuanke.com/t/30996 线段树维护区间最小值,查询的时候优先向左走,如果左边已经找到了,就不用再往右了. 一个房间装满则把权值标记为INF,模拟一遍,注意考虑一个月内装满多个房间和装满所有房间后不用再购买的情况. 代码: #include <iostream> #include <cstdio> #include <algorithm> const int maxn = 100005; const int INF = 0x3

Balanced Lineup(线段树之区间查找最大最小值)

传送门 线段树的区间查找最大最小值模板. 裸的线段树 #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <set> #include <queue> #include <vector> #include <cstdlib> #include <algorithm> #define ls

CodeForces 52C Circular RMQ(区间循环线段树,区间更新,区间求和)

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://codeforces.com/problemset/problem/52/C You are given circular array a0,?a1,?...,?an?-?1. There are two types of operations with it: inc(lf,?rg,?v) - this operation increases each element on the segm

基本线段树模板(建树、点/区间修改、查询)

线段树主要用于区间记录信息(如区间和.最大最小值等),首先是建树: 这里以求和为例: 1 const int MAXM=50000; //定义 MAXM 为线段最大长度 2 3 int a[MAXM+5],segtree[(MAXM<<2)+5]; // a 数组为 main 函数中读入的内容,segtree 数组为需要查询的数的信息(如和.最值等),树的空间大小为线段最大长度的四倍 4 5 void build(int o,int l,int r){ //传入的参数为 o:当前需要建立的结点

POJ 3468 A Simple Problem with Integers(线段树模板之区间增减更新 区间求和查询)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 140120   Accepted: 43425 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type o

[POJ2104] 区间第k大数 [区间第k大数,可持久化线段树模板题]

可持久化线段树模板题. #include <iostream> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <ctime> #include <vector> using namespace std; int n,q,tot,a[110000]; in

模板 线段树的区间修改

线段树的区间修改 区间绝对标记 改成同一个数 注意打标记前 要先判断 是否有标记 这道题不能像加法标记一样 标记初始化为 0 如果这道题 可以将数变成 0 那么0 就不能为初始值了 然后我们初始值要选择一个不会被干扰到的数字 比如 -1 就不会变成 -1 另外还要注意在标记清空时 要将标记 变成 -1 而不是 0 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstr