GDOI2014 吃(D1T3) 线段树

3644. 【GDOI2014】吃 (Standard IO)

Time Limits: 2000 ms  Memory Limits: 262144 KB

Description

W师兄计划了很久,终于成功的在BG开了一家寿司店。

正当W师兄还在兴奋的时候,这时一个噩耗传来,吃货L师姐居然知道了这件事,而且正赶过来,W师兄瞬间心就冷了下去,但是机智的W师兄也瞬间想到了应付L师姐的策略.......

这时,L师姐到了寿司店,先四处望了望风景,发现现在只有L师姐一个顾客,下面是L师姐的选餐说明:

1.寿司店内的寿司被排在一行共N个盘子里,按从左到右编号为1~N。

2.每个位置上寿司的数量是确定的并且有玻璃窗保护。

3.每隔一段时间就会有一个选餐时间,L师姐可以在一个连续的区间[l, r]中选择其中一盘,然后在该区间之外选择另一盘(如果区间外有盘子)。

L师姐发现这家寿司店厨师的制作速度很快,总能在下一次选餐时间前将寿司数量恢复原样。

作为有尊严有追求的吃货,L师姐也有自己的规则,L师姐在选完两盘寿司后,会决定每口恰好吃D个寿司,且使得两盘寿司刚好可以分别吃完,不剩余任何寿司。比如两盘寿司数量为2和4,那么D=1或者D=2都可以恰好将两盘寿司分别吃干净,而两盘寿司数量为3和5时,那么只能D=1才行。

作为有特殊追求的L师姐才不在乎吃的数量,L师姐在乎的是一口吃多个寿司的感觉。于是,如果L师姐可以一口吃D个寿司,那么L师姐的愉悦值为D,但是L师姐没有选到两盘寿司,那么她的愉悦值为0。

现在L师姐知道每个盘子所放着的寿司数量,L师姐想知道每次选择时间过后她可以获得的最大愉悦值是多少?

Input

第一行输入一个整数N,表示寿司的盘子数量。

第二行输入N个整数a1,a2,…,aN,ai表示第i个盘子内的寿司数量。

第三行输入一个整数M,表示有多少个选餐时间。

接下来M行,每行两个整数li, ri (1 <= li <= ri <= N),含义如题面所示。

Output

输出M行,第i行表示第i个选择时间师姐可能达到的最大愉悦值D。

Sample Input

输入1:

5

1 2 3 4 5

2

2 3

2 4

输入2:

5

2 4 8 16 32

2

3 4

2 3

Sample Output

输出1:

2

1

输出2:

16

8

样例解释:

样例1里的第一个选餐时间,可以选择2和4,这样L师姐就可以每次吃两个寿司,使得两个盘子都可以吃干净,第二个选餐时间,师姐不管选哪两个盘子,都只能每次吃一个。

样例2 里的第一个选餐时间,可以选择16和32,而第二个选餐时间,L师姐可以选择8和16或者8和32。

Data Constraint

对于20%的数据,N <= 100, M <= 100, max(a1,a2,…,aN) <= 100。

对于50%的数据,N <= 10000, M <= 10000, max(a1,a2,…,aN) <= 10000。

对于100%的数据,N <= 100000, M <= 100000, max(a1,a2,…,aN) <= 100000。

用pre[][i][j]记录每个数离a[i]最近的(前/后)含有它的第j个因子的数。然后把询问排序离线处理,用线段树f[i]记录在范围之前/之后的数中与i的最大gcd

正着做一次统计(1-l-1,l-r)的maxgcd,反着做一次统计(l-r,r+1-n)的maxgcd即可

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>

using namespace std;

int f[800111];
int pre[2][100111][101],can[100111][101];
int hash[100111];
int n,m,tot,i,j,k,last;
int ans[100111],a[100111];

struct data{
    int l,r,id;
}q[100111];

bool cmp(data a,data b)
{
    return a.l<b.l;
}

bool cmp2(data a,data b)
{
    return a.r>b.r;
}

void insert(int l,int r,int x,int y,int t)
{
    int mid;
    if(l==r){
        f[t]=max(f[t],y);
        return;
    }
    mid=(l+r)/2;
    if(x<=mid)insert(l,mid,x,y,t+t);
    if(x>mid)insert(mid+1,r,x,y,t+t+1);
    f[t]=max(f[t+t],f[t+t+1]);
}

int ask(int l,int r,int x,int y,int t)
{
    int mid;
    if(l==x&&r==y)return f[t];
    mid=(l+r)/2;
    if(y<=mid)return ask(l,mid,x,y,t+t);
    if(x>mid)return ask(mid+1,r,x,y,t+t+1);
    if(x<=mid&&y>mid)return max(ask(l,mid,x,mid,t+t),ask(mid+1,r,mid+1,y,t+t+1));
}

int main()
{
    scanf("%d",&n);
    for(i=1;i<=n;i++)scanf("%d",&a[i]);
    memset(hash,0,sizeof(hash));
    for(i=1;i<=n;i++){
        tot=0;
        for(j=1;j<=(int)sqrt(a[i]);j++)if(a[i]%j==0){
            tot++;
            pre[0][i][tot]=hash[j];
            can[i][tot]=j;
            hash[j]=i;
            k=a[i]/j;
            if(j!=k){
                tot++;
                can[i][tot]=k;
                pre[0][i][tot]=hash[k];
                hash[k]=i;
            }
        }
        can[i][0]=tot;
    }
    memset(hash,0,sizeof(hash));
    for(i=n;i>=1;i--){
        tot=0;
        for(j=1;j<=(int)sqrt(a[i]);j++)if(a[i]%j==0){
            tot++;
            can[i][tot]=j;
            pre[1][i][tot]=hash[j];
            hash[j]=i;
            k=a[i]/j;
            if(k!=j){
                tot++;
                can[i][tot]=k;
                pre[1][i][tot]=hash[k];
                hash[k]=i;
            }
        }
        can[i][0]=tot;
    }
    scanf("%d",&m);
    for(i=1;i<=m;i++){
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    sort(q+1,q+1+m,cmp);
    last=1;
    memset(f,0,sizeof(f));
    for(i=1;i<=m;i++){
        for(j=last;j<q[i].l;j++)
            for(k=1;k<=can[j][0];k++)if(pre[1][j][k])insert(1,n,pre[1][j][k],can[j][k],1);
        ans[q[i].id]=ask(1,n,q[i].l,q[i].r,1);
        last=q[i].l;
    }
    memset(f,0,sizeof(f));
    sort(q+1,q+1+m,cmp2);
    last=n;
    for(i=1;i<=m;i++){
        for(j=last;j>q[i].r;j--)
            for(k=1;k<=can[j][0];k++)if(pre[0][j][k])insert(1,n,pre[0][j][k],can[j][k],1);
        ans[q[i].id]=max(ans[q[i].id],ask(1,n,q[i].l,q[i].r,1));
        last=q[i].r;
    }
    for(i=1;i<=m;i++)printf("%d\n",ans[i]);
}
时间: 2024-10-30 02:34:51

GDOI2014 吃(D1T3) 线段树的相关文章

苹果树(线段树+Dfs序)

1228 苹果树 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 在卡卡的房子外面,有一棵苹果树.每年的春天,树上总会结出很多的苹果.卡卡非常喜欢吃苹果,所以他一直都精心的呵护这棵苹果树.我们知道树是有很多分叉点的,苹果会长在枝条的分叉点上面,且不会有两个苹果结在一起.卡卡很想知道一个分叉点所代表的子树上所结的苹果的数目,以便研究苹果树哪些枝条的结果能力比较强. 卡卡所知道的是,每隔一些时间,某些分叉点上会结出一些苹果,但

【BZOJ1984】月下“毛景树” 树链剖分+线段树

[BZOJ1984]月下"毛景树" Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里.爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的"毛景树"下面,发现树上长着他最爱吃的毛毛果~~~ "毛景树"上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵"毛景树"有着神奇的魔力,他能改变树枝上毛毛果的个数: ?

ZOJ3632 线段树+DP

买西瓜吃,每个西瓜有两个参数,一个是p代表价格,一个是t代表能吃几天,要求n天每天都能吃西瓜,而且如果你今天买了,以前买的还没吃完 那么都得扔了,求最小花费,还真想不到用线段树+DP,最后看了一下别人的标题,想了一下,DP方程挺好推的,线段树也只是单点查询, #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #inclu

tyvj P1716 - 上帝造题的七分钟 二维树状数组区间查询及修改 二维线段树

P1716 - 上帝造题的七分钟 From Riatre    Normal (OI)总时限:50s    内存限制:128MB    代码长度限制:64KB 背景 Background 裸体就意味着身体. 描述 Description “第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵.第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作.第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作.第

(转)线段树的区间更新

原文地址:http://blog.csdn.net/zip_fan/article/details/46775633 写的很好,昨天刚刚开始写线段树,有些地方还不是很明白,看了这篇博文,学会了数组形式保存线段树,还学会了区间更新 以下为转载的博文内容 距离第一次接触线段树已经一年多了,再次参加ACM暑假集训,这一次轮到我们这些老家伙们给学弟学妹们讲解线段树了,所以就自己重新把自己做过的题目看了一遍,然后写篇博客纪念一下.作为一个菜鸟,文中肯定有很多表达不是很准确甚至错误的地方,欢迎各位大牛指正.

【BZOJ-3638&amp;3272&amp;3267&amp;3502】k-Maximum Subsequence Sum 费用流构图 + 线段树手动增广

3638: Cf172 k-Maximum Subsequence Sum Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 174  Solved: 92[Submit][Status][Discuss] Description 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. Input The first line contains integer n (1 ≤ n 

HDU 4302 线段树单点更新,维护区间最大最小值

http://acm.hdu.edu.cn/showproblem.php?pid=4302 Problem Description Holedox is a small animal which can be considered as one point. It lives in a straight pipe whose length is L. Holedox can only move along the pipe. Cakes may appear anywhere in the p

HDU 4302 线段树

点击打开链接 题意:在一个0到L的坐标上,0是在某个位置摆个蛋糕,然后1是吃蛋糕,但是吃的必须是离自己最近的,若没有蛋糕就不动,若有两个蛋糕与其距离相等,那么我们选择上一步的方向来吃蛋糕,问最后这个人走了多远 思路:用两个队列应该就可以很简单的完成,但是想到了线段树,就写个线段树,而线段树一样维护的是最大值和最小值,不过这两个值都是对应的位置,那么对于队列来说肯定就是也维护这两个值,然后讨论处理一下就行了 #include <stdio.h> #include <string.h>

HDU4509-湫湫系列故事——减肥记II(线段树)

湫湫系列故事--减肥记II Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 2395    Accepted Submission(s): 1018 Problem Description 虽然制定了减肥食谱,但是湫湫显然克制不住吃货的本能,根本没有按照食谱行动! 于是,结果显而易见- 但是没有什么能难倒高智商美女湫湫的,她决定另寻对策