hdu6107 倍增法st表

发现lca的倍增解法和st表差不多。。原理都是一样的

/*
整篇文章分成两部分,中间没有图片的部分,中间有图片的部分
分别用ST表求f1,f2表示以第i个单词开始,连续1<<j行能写多少单词
*/
#include<bits/stdc++.h>
#define FIN freopen("in.txt","r",stdin);
using namespace std;
#define ll long long
#define MX 100005
#define inf 0x3f3f3f3f
int mx,n,w,dw,pw,a[MX];
int f1[MX][30],f2[MX][30];
void ST(){
    for(int i=1;i<=n;i++){//只填一行的状态
        int cnt=a[i],j=i+1;
        while(cnt+a[j]+1<=w && j<=n) cnt+=a[j++]+1;
        f1[i][0]=j-i;
    }
    for(int j=1;(1<<j)<=mx;j++)
        for(int i=1;i<=n;i++)
            f1[i][j]=f1[i][j-1]+f1[i+f1[i][j-1]][j-1];

    for(int i=1;i<=n;i++){
        int cnt=0,j=i,flag=0;
        while(cnt+a[j]+flag<=dw)//图片的左端能填入的单词
            cnt+=a[j++]+flag,flag=1;//填入第一个单词后下一个单词就要空一格了
        int k=j;
        cnt=flag=0;
        while(cnt+a[k]+flag<=w-pw-dw)//图片右端能填入的单词
            cnt+=a[k++]+flag,flag=1;
        f2[i][0]=k-i;
    }
    for(int j=1;(1<<j)<=mx;j++)
        for(int i=1;i<=n;i++)
            if(f2[i][j-1]==0) f2[i][j]=0;//第i个单词无法填入有图片的行
            else f2[i][j]=f2[i][j-1]+f2[i+f2[i][j-1]][j-1];
}
int RMQ1(int i,int x){//i是当前填的单词下标,x是可以填的行数,返回当前填到了第几个单词
    if(x==0) return i;
    while(x && i<=n){
        int j=0;
        while((1<<(j+1))<=x)j++;//先求出最大的j
        i+=f1[i][j]; x-=(1<<j);
    }
    return i;
}
int RMQ2(int i,int x){
    if(x==0) return i;
    while(x && i<=n){
        int j=0;
        while((1<<(j+1))<=x) j++;
        i+=f2[i][j];x-=(1<<j);
    }
    return i;
}
int RMQ3(int i){//返回填i-n个单词需要的行数
    int ret=0;
    while(i<=n){
        int j=0;
        while(i+f1[i][j+1]<=n) j++;//找到最大的j
        i+=f1[i][j];
        ret+=(1<<j);
    }
    return ret;
}
struct Query{
    int x,h;
}q[MX];
int main(){
    int T,m;
    cin >> T;
    while(T--){
        scanf("%d%d%d%d",&n,&w,&pw,&dw);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        scanf("%d",&m);
        mx=n;
        for(int i=1;i<=m;i++) {
            scanf("%d%d",&q[i].x,&q[i].h);
            mx=max(mx,n+q[i].x+q[i].h);
        }
        ST();
        for(int i=1;i<=m;i++){
            int x=q[i].x,h=q[i].h;
            int tmp=RMQ3(1);//只用f1
            if(tmp<=x-1){
                printf("%d\n",tmp+h);
                continue;
            }
            int ans=x+h-1;
            int p=RMQ1(1,x-1);//从第一个单词开始连续x-1行能填的单词书
            p=RMQ2(p,h);//从第p个单词开始连续h行能填的单词数
            if (p<=n) ans+=RMQ3(p);//把剩下的单词填进去
            printf("%d\n",ans);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/zsben991126/p/10016417.html

时间: 2024-08-29 15:24:29

hdu6107 倍增法st表的相关文章

CF1190E Tokitsukaze and Explosion 二分、贪心、倍增、ST表

传送门 最小值最大考虑二分答案,不难发现当最小值\(mid\)确定之后,原点到所有直线的距离一定都是\(mid\)时才是最优的,也就是说这些直线一定都是\(x^2+y^2=mid^2\)的切线. 接下来考虑一个点会被哪些切线所保护.作出这个点到圆的公切线,得到两个切点,那么在这两个切点之间的优弧上选择一个点,以它为切点的切线就可以保护当前点.也就是说能够保护一个点的切线的切点在圆上表现为一段角度的区间.可以用解析几何计算出这个角度的区间. 接下来需要在\([-\pi , \pi]\)上选择不超过

倍增思想到ST表RMQ

Balanced Lineup Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 36864   Accepted: 17263 Case Time Limit: 2000MS Description For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer Joh

【倍增】RMQ的ST表算法

RMQ问题:给定一个长度为N的区间,M个询问,每次询问Li到Ri这段区间元素的最大值/最小值. RMQ的高级写法一般有两种,即为线段树和ST表. 本文主要讲解一下ST表的写法.(以区间最大值为例) ST表:一种利用dp求解区间最值的倍增算法. 定义:f[i][j]表示i到i+2^j-1这段区间的最大值. 预处理:f[i][0]=a[i].即i到i区间的最大值就是a[i]. 状态转移:将f[i][j]平均分成两段,一段为f[i][j-1],另一段为f[i+2^(j-1)][j-1]. 两段的长度均

51nod2621 树上距离一题四解ST表+倍增+Tarjan+树剖

LCA裸题 只有代码无原理,给自己复习用 1. ST表(这题2^10就够了) 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=2e3+50; 5 6 int cnt,dfn[maxn],dep[maxn],dp[maxn][21],lg2[maxn],dis[maxn],w[maxn][maxn]; 7 std::vector<int> G[maxn]; 8 void dfs(int u,in

[模板]ST表浅析

ST表,稀疏表,用于求解经典的RMQ问题.即区间最值问题. Problem: 给定n个数和q个询问,对于给定的每个询问有l,r,求区间[l,r]的最大值.. Solution: 主要思想是倍增和区间dp. 状态:dp[i][j] 为闭区间[i,i+2^j-1]的最值. 这个状态与转移方程的关系很大,即闭区间的范围涉及到了转移方程的简便性. 转移方程:dp[i][j]=max(dp[i][j-1],dp[i+2^(j-1)][j-1]). 这是显然的,但这里有个细节:第一个项的范围为[i,i+2^

说一说ST表 讲一讲水题

ST表 一.算法介绍 如何快速求解RMQ问题呢?暴力复杂度O(n),线段树复杂度O(n)~O(logn),要是数据规模达到10^7或者更高呢?我们需要一种可以做到O(1)查询的算法,这时就可以用到ST表. 我们用 f[i][j] 表示从 j 位置开始往右 2^i 个数内的最大值,用 g[i][j] 表示从j位置开始往左 2^i 个数内的最大值.所以 f[0][j] , g[0][j] 就为 j 位置上的数,可以在预处理中O(n)处理掉. 接下来我们要求出每个位置的每个 2^i 区间的最大值.可以

【BZOJ-4569】萌萌哒 ST表 + 并查集

4569: [Scoi2016]萌萌哒 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 459  Solved: 209[Submit][Status][Discuss] Description 一个长度为n的大数,用S1S2S3...Sn表示,其中Si表示数的第i位,S1是数的最高位,告诉你一些限制条件,每个条件表示为四个数,l1,r1,l2,r2,即两个长度相同的区间,表示子串Sl1Sl1+1Sl1+2...Sr1与Sl2Sl2+1Sl2+2.

poj1330Nearest Common Ancestors以及讲解倍增法求lca

Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20487   Accepted: 10784 Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below: In the figure, each node is labeled with an

POJ 3613Cow Relays( floyd 倍增法)

题意:从s点出发到达e点且n条边的最短路是多少(可以走重复的路径) 图中点<=200,n<=1000,000 思路:folyd可以实现向路径中添边,但是这题与普通的求最短路问题不一样,比如从S到E经过X条边后就已经达到了最短路,这个时候仍然要强制用folyd再添边,尽管添边后就不是最短路了,但是要注意到添加的这边要使最短路损失最小,抓住这点用folyd可以实现强制添边的操作,所以可以从n=1的状态向n的状态转移 所以可以对原来的map进行n-1次folyd,但是n的范围太大,最坏的情况要进行1