饥饿游戏

(hungry.pas/c/cpp)

【问题描述】

Chanxer饿了,但是囊中羞涩,于是他去参加号称免费吃到饱的“饥饿游戏”。

这个游戏的规则是这样的,举办者会摆出一排 个食物,希望你能够一口就吃完。

然而Chanxer却不这么想,比起数量,他更看重质量,对于没一个食物,都会有一个喜爱值,Chanxer希望能够吃到最美味的那一段。

注意,因为只能吃一口,因此Chanxer只有一次机会,即只能吃连续的一段,因为他的嘴够大,因此无论这一段有多长,他都可以吃到。

不过Chanxer是一个喜新厌旧的男人,对于多个喜爱值相同的食物,他会只算作一次,比如: ,2出现了3次,但只算一次,于是这一段的喜爱值是 。

现在Chanxer对于吃哪一段有很多想法,每一个想法他都想要试试,但是由于只有一次机会,所以他想要你先帮他算算这些他想要吃的段带给他的喜爱值是多少。

【输入】

输入文件名为hungry.in,共 行。

第一行包含一个整数 n。

接下来一行,n个整数,第i个数表示第i个食物的喜爱值a。

接下来一行包含一个整数 m ,表示Chanxer的询问个数。

接下来 m行,每行两个数 l,r,表示Chanxer要询问这个区间的喜爱值【注意是指这个区间内的最优值】。

【输出】

输出文件名为hungry.out,共M行。

每行一个整数表示此次询问的答案。

【输入输出样例】

hungry.in

hungry.out

9

4 -2 -2 3 -1 -4 2 2 -6

3

1 2

1 5

4 9

4

5

3

【数据说明】

对于 的数据满足,n,m<=100;

对于 的数据满足, n,m<=100,000,|ai|<=100,000。

【分析】这题当场最高30分....结果还没有solution ! 无奈只能Orz std的代码了... 然而std的代码高能——使用zkw线段树....

  多亏我当初还是看过一些zkw线段树...于是拉上Zero去黑板上进行模拟运算....画了两棵巨大的线段树...终于半猜半模拟的弄懂了std的思路,爽啊!

  

  正解的具体思路:

  1.发现每次询问[L,R]中的最优值,无非是另一个直接取的一个小的区间 [l,r]满足 l>=L && r<=R。

  2.因为相同的数在一段区间内只会加一次,所以每次在两个相邻的相同的数之间加入这个数。

  

  【经过这两个比较核心的思路】

  STD设计了一个线段树来每次获得最优值。

  每次移动右端点,每次将右端点的值添加进线段树更新一段区间[pre[i]+1,i]的最优值。

  其中每个叶子节点带有两个属性:g[i],f[i]

    g[i]表示从i到当前枚举的最右端点能获得的最优值[但是要求必须选择i这个节点作为左端点],右端点是不固定的。

    f[i]表示从i到当前枚举的最右端点的总和[要求左端点为i,右端点为当前枚举的最右端点],左右端点都是固定的。

    所以可以想到g[i]每次都是由f[i]更新的。

  但是每次这样传到每个叶节点太慢了,于是利用线段树的方法,每次给一段区间添加一个值时,使用lazy_tag,也就是说每个非叶节点多了两个属性: gd[i],fd[i]

  而每个非叶节点还表示这个区间内元素,所以它们也具有一个g[],f[]的意义

    g[i]表示以i能控制的区间内的任意元素作为左端点到当前枚举右端点能获得的最优值 [即i控制区间内g[]的最优值]

    f[i]表示以i能控制的区间内的任意元素作为左端点,当前枚举右端点作为区间右端点能获得的最优值 [即i控制区间内f[]的最优值]

    gd[i]表示对于i能控制的区间内曾经可以添加的最多的值 [也就是没来得及下传的最好的一次 tag]

    fd[i]表示对于i控制的区间内到现在为止累积的值 [也就是每次累加得到的值而已]

    所以也可以想到gd[i]是由fd[i]更新的。

  可以发现每次再添加tag的时候需要下传一些 tag,和线段树一样。

  下传的时候更新下面节点的tag,gd[]由gd[fa]+fd[]更新,fd变成fd[fa]+fd[]

  下传时还要更新下面节点的g[]和f[],其中g[]由gd[fa]+f[]更新,f[]变成fd[fa]+f[]

  

  现在每个答案就比较好求了,因为代表的意义有当前右端点存在的影响,需要离线处理,将询问按右端点排序,然后枚举右端点,如果右端点与某个r重合,查询[l,r]内的最优g[]即可。

 #include<cstdio>
#include<cstdlib>
#include<algorithm> using namespace std; typedef long long ll;
const int nmax=,tmax=<<,shift=nmax; int n,m;
int M=,H=;
int a[nmax+],last[nmax*+],pre[nmax+];
ll f[tmax+],g[tmax+],fd[tmax+],gd[tmax+],ans[nmax+];
int l[nmax+],r[nmax+],p[nmax+]; bool cmp(int i,int j){
return r[i]<r[j];
} inline int max(int a,int b) {return a>b?a:b;} inline void update(ll &a,ll b){if(a<b) a=b;} inline void take(int i){
f[i]=max(f[i<<],f[i<<|]),g[i]=max(g[i<<],g[i<<|]);
} inline void give(int i,int j){
//fd[i]和gd[i]在于之前添加时可能没有顾及到下面的节点,于是偷懒加上tag表示这里可以下传的数目;
//其中gd[i]表示的是历史上给i的子树能添加的最大值,fd[i]表示总计能给它们添加多少
update(g[i],f[i]+gd[j]),f[i]+=fd[j];
update(gd[i],fd[i]+gd[j]),fd[i]+=fd[j];
} void pd(int i){
for(int h=H-,j;h;--h)//枚举i的所有祖先将它们的 tag下传
if(fd[j=i>>h] || gd[j])
give(j<<,j),give(j<<|,j),fd[j]=gd[j]=;
} void add(int l,int r,int x){
//f[i]表示计算从i到当前枚举值的整段之和
//g[i]表示必须选择i为左端点的情况下,到当前枚举值间的最优值。
//若g[i]不为叶子节点,则g[i]表示以其代表区间内的任意元素作为左端点的最优值
//f[i]不为叶节点时等于示以其代表区间内的任意元素作为左端点且当前枚举点为右端点时的最优值
for(pd(l+=M-),pd(r+=M+)/*传递(L,R)之间的所有标记*/;l^r^;take(l>>=),take(r>>=)/*这里只能传到 L,R会合之下的两端*/){ //因为不能每次传到底,所以给包含区间加上tag标记
if(~l&)
update(g[l^],f[l^]+=x),update(gd[l^],fd[l^]+=x);
if(r&)
update(g[r^],f[r^]+=x),update(gd[r^],fd[r^]+=x);
}
for(int tmp1,tmp2;l>>=;){//所以这里需要往上带到根节点去
tmp1=f[l],tmp2=g[l];
take(l);
if(f[l]==tmp1 && g[l]==tmp2) break;
}
} ll getmax(int l,int r){
//每次从l,r中选任意一个节点作为左端点,右端点不固定时的最优值即为答案。
ll Ans=;
for(pd(l+=M-),pd(r+=M+);l^r^;l>>=,r>>=){
if(~l&) update(Ans,g[l^]);
if(r&) update(Ans,g[r^]);
}
return Ans;
} int main(){
freopen("hungry.in","r",stdin);
freopen("hungry.out","w",stdout);
scanf("%d", &n);
while(n>=M-) M<<=,++H;
for(int i=;i<=n;i++)
scanf("%d",a+i),pre[i]=last[a[i]+shift],last[a[i]+shift]=i;//pre[i]表示上一个和它相同数所在的位置
scanf("%d",&m);
for(int i=;i<=m;i++)
scanf("%d%d",l+i,r+i),p[i]=i;
sort(p+,p+m+,cmp);//给右区间排序,因为g[x]表示的是从x开始,必须选x到当前枚举值之间的最优值,而当前枚举值相当于区间的右端点 for(int i=,j=;i<=n && j<=m;i++)
for(add(pre[i]+,i,a[i])/*往两个相同的数之间加,这样可以使重复的数只加一次*/;j<=m && r[p[j]]<=i;j++)
ans[p[j]]=getmax(l[p[j]],r[p[j]]); for(int i=;i<=m;i++)
printf("%I64d\n",ans[i]);
return ;
}

  Orz 人类智慧的伟大...+数据结构的巧妙结合...

Noip模拟考第三题——饥饿游戏的更多相关文章

  1. NOI.AC NOIP模拟赛 第三场 补记

    NOI.AC NOIP模拟赛 第三场 补记 列队 题目大意: 给定一个\(n\times m(n,m\le1000)\)的矩阵,每个格子上有一个数\(w_{i,j}\).保证\(w_{i,j}\)互不 ...

  2. noip模拟23[联·赛·题]

    \(noip模拟23\;solutions\) 怎么说呢??这个考试考得是非常的惨烈,一共拿了70分,为啥呢 因为我第一题和第三题爆零了,然后第二题拿到了70分,还是贪心的分数 第一题和第二题我调了好 ...

  3. noip模拟35[第一次4题·裂了]

    noip模拟35 solutions 这是我第一次这么正式的考四个题,因为这四个题都出自同一个出题人,并不是拼盘拼出来的. 但是考得非常的不好,因为题非常难而且一直想睡觉.. 有好多我根本就不会的算法 ...

  4. noip模拟4[随·单·题·大佬]

    woc    woc   woc难斩了人都傻了 害上来先看T1,发现这不就是一个小期望嘛(有啥的)真是!!打算半个小时秒掉 可是吧,读着读着题面,发现这题面有大问题,后来去找老师,还是我nb给题挑错, ...

  5. NOIP 模拟 $13\; \text{玄学题}$

    题解 题如其名,是挺玄学的. 我们发现每个值是 \(-1\) 还是 \(1\) 只与它的次数是奇是偶有关,而 \(\sum_j^{j\le m}d(i×j)\) 又只与其中有多少个奇数有关 对于 \( ...

  6. NOIP 模拟 $13\; \text{工业题}$

    题解 本题不用什么推式子,找规律(而且也找不出来) 可以将整个式子看成一个 \(n×m\) 矩阵 考虑 \(f_{i,j}\),它向右走一步给出 \(f_{i,j}×a\) 的贡献,向下走一步给出 \ ...

  7. NOIP模拟13「工业题·卡常题·玄学题」

    T1:工业题 基本思路   这题有一个重要的小转化: 我们将原来的函数看作一个矩阵,\(f(i,j-1)*a\)相当于从\(j-1\)向右走一步并贡献a,\(f(i-1,j)*b\)相当于从\(i-1 ...

  8. Newnode's NOI(P?)模拟赛 第三题 (主席树优化建图 + tarjan)

    题目/题解戳这里 这道题题目保证a,b,ca,b,ca,b,c各是一个排列-mdzz考场上想到正解但是没看到是排列,相等的情况想了半天-然后写了暴力60分走人- 由于两两间关系一定,那么就是一个竞赛图 ...

  9. NOIP模拟 29

    T1第一眼觉得是网络流 看见4e6条边200次增广我犹豫了 O(n)都过不去的赶脚.. 可是除了网络流板子我还会什么呢 于是交了个智障的EK 还是用dijkstra跑的 居然有50分!$(RP--)$ ...

随机推荐

  1. 开始安装 ASP.NET (4.0.30319.18408)。 出现了错误: 0x8007b799 必须具有此计算机的管理员权限才能运行此工具

    在Visual Studio命令提示符安装ASP.NET .出现了错误: 0x8007b799 必须具有此计算机的管理员权限才能运行此工具:如下图: 解决方案如下: 1.打开“C:\Windows\S ...

  2. 获取屏幕分辨率(C#)

    C#获取屏幕分辨率的方法 static void Main(string[] args) { // 控制台程序,需要添加程序集: // using System.Drawing; // using S ...

  3. QQl聊天消息

    Activity: package com.zzw.qqchat; import java.util.ArrayList; import java.util.HashMap; import andro ...

  4. JDBC基础一

    JDBC:java database connectivity SUN公司提供的一套操作数据库的标准规范. JDBC与数据库驱动的关系:接口与实现的关系. JDBC规范(掌握四个核心对象): Driv ...

  5. SRF之日志和异常

    日志: 日志功能采用log4net实现 log4配置文件在站点目录下的log4net.config. 调用log4写日志的代码如下: log4net.ILog logger = log4net.Log ...

  6. (转)Android网络命令

    转自:http://www.cnblogs.com/shunyao8210/archive/2010/08/10/1796214.html ifconfig 1.       作用 ifconfig用 ...

  7. ORA-01207: file is more recent than control file -

    OS: [root@yoon ~]# more /etc/oracle-releaseOracle Linux Server release 5.7 DB: Oracle Database 11g E ...

  8. 向plsql中导入数据

    1.TOOLS-->ODBC IMPORTER 2.TOOLS-->TEXT IMPORTER3.sqlldr userid=zj/zj@orcl control=D:\test.ctl ...

  9. 快速的搭建JFinal的ORM框架示例

    JFinal默认用的是Freemarker作为视图. 所以,打架还是准备好俩个jar包吧! freemarker-2.3.16.jar JFinal-bin-1.5.jar 新建web工程和添加lib ...

  10. Erlang generic standard behaviours -- gen

    在分析 gen_server (或者是gen_fsm )之前,首先应该弄明白,gen 这个module . -module(gen). -compile({inline,[get_node/1]}). ...