• [Luogu] CF515E Drazil and Park


    (Link)

    Description

    有一只猴子,他生活在一个环形的公园里。有(n)棵树围绕着公园。第(i)棵树和第(i+1)棵树之间的距离是(d_i),而第(n)棵树和第一棵树之间的距离是(d_n)。第(i)棵树的高度是(h_i)​ 。

    这只猴子每天要进行晨跑。晨跑的步骤如下:

    • 他先选择两棵树;
    • 然后爬上第一棵树;
    • 再从第一棵树上下来,接着围绕着公园跑(有两个可能的方向)到第二棵树,然后爬上第二棵树;
    • 最后从第二棵树上下来。

    但是有一些小孩会在连续的一些树上玩耍。所以猴子不能经过这些树。

    比如现在猴子选择的第(x)棵和第(y)棵树,那么该早晨他消耗的能量是(2(h_x+h_y)+dist(x,y)) 。由于某一条路径是被小孩子占据的,所以他只能跑另外一条,因此(dist(x,y))是确定的。

    现在给出第(i)天,孩子们会在第(a_i)棵树和(b_i)棵树之间玩耍。具体的,如果(a_i≤b_i) ,那么孩子玩耍的区间就是 ([a_i,b_i]),否则孩子玩耍的区间就是([ai,n]⋃[1,bi])

    请帮助这只猴子找出两棵树,让他晨跑的时候他能够消耗最大的能量。

    Solution

    可能会想到分别最大化,但这时求出来的((x,y))很有可能不是同一对。

    所以先断环成链,再对(d_i)做一遍前缀和。这时题目就转化为最大化(2h_x+2h_y+sum_y-sum_x)。套路:把(x)(y)的项分别处理,这时要使(2h_y+sum_y)最大,(sum_x-2h_x)最小。预处理(ST)表即可。

    要注意首先要依据题意,对询问区间求补集,然后算出来的(x)(y)可能是一样的,不符合题意,这时只需在([l,pos-1])([pos+1,r])中分别查询最值,在计算比较即可。所以(ST)表维护的是最值的下标。

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    
    int n, m, lg[200005], d[200005], h[200005];
    
    ll s1[200005], s2[200005], sum[200005], mn[200005][20], mx[200005][20];
    
    int read()
    {
    	int x = 0, fl = 1; char ch = getchar();
    	while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
    	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
    	return x * fl;
    }
    
    int query1(int x, int y)
    {
    	if (x > y) return 0;
    	int k = lg[y - x + 1];
    	ll p = s1[mx[x][k]], q = s1[mx[y - (1 << k) + 1][k]];
    	if (p > q) return mx[x][k];
    	else return mx[y - (1 << k) + 1][k];
    }
    
    int query2(int x, int y)
    {
    	if (x > y) return 0;
    	int k = lg[y - x + 1];
    	ll p = s2[mn[x][k]], q = s2[mn[y - (1 << k) + 1][k]];
    	if (p < q) return mn[x][k];
    	else return mn[y - (1 << k) + 1][k];
    }
    
    int main()
    {
    	n = read(); m = read();
    	for (int i = 1; i <= n; i ++ )
    	{
    		d[i % n + 1] = read();
    		d[i % n + n + 1] = d[i % n + 1];
    	}
    	for (int i = 1; i <= n; i ++ )
    	{
    		h[i] = read();
    		h[i] <<= 1;
    		h[i + n] = h[i];
    	}
    	for (int i = 1; i <= (n << 1); i ++ )
    		sum[i] = sum[i - 1] + (ll)(d[i]), lg[i] = (int)(log2((double)(i)));
    	s1[0] = -2e15; s2[0] = 2e15;  
    	for (int i = 1; i <= (n << 1); i ++ )
    	{
    		s1[i] = sum[i] + h[i];
    		s2[i] = sum[i] - h[i];
    		mn[i][0] = mx[i][0] = i; 
    	}
    	for (int j = 1; j <= 19; j ++ )
    	{
    		for (int i = 1; i + (1 << j) <= (n << 1); i ++ )
    		{
    			ll x, y;
    			x = s1[mx[i][j - 1]], y = s1[mx[i + (1 << (j - 1))][j - 1]];
    			if (x > y) mx[i][j] = mx[i][j - 1]; else mx[i][j] = mx[i + (1 << (j - 1))][j - 1];
    			x = s2[mn[i][j - 1]], y = s2[mn[i + (1 << (j - 1))][j - 1]];
    			if (x < y) mn[i][j] = mn[i][j - 1]; else mn[i][j] = mn[i + (1 << (j - 1))][j - 1];
    		}
    	}
    	while (m -- )
    	{
    		int l = read(), r = read(), pos1, pos2;
    		if (l <= r) pos1 = query1(r + 1, l + n - 1), pos2 = query2(r + 1, l + n - 1);
    		else pos1 = query1(r + 1, l - 1), pos2 = query2(r + 1, l - 1);
    		if (pos1 != pos2) printf("%lld
    ", s1[pos1] - s2[pos2]);
    		else
    		{
    			int pos3, pos4; ll res1, res2;
    			if (l <= r)
    			{
    				pos3 = query1(r + 1, pos1 - 1), pos4 = query1(pos1 + 1, l + n - 1), res1 = max(s1[pos3], s1[pos4]) - s2[pos2];
    				pos3 = query2(r + 1, pos2 - 1), pos4 = query2(pos2 + 1, l + n - 1), res2 = s1[pos1] - min(s2[pos3], s2[pos4]);
    			}
    			else
    			{
    				pos3 = query1(r + 1, pos1 - 1), pos4 = query1(pos1 + 1, l - 1), res1 = max(s1[pos3], s1[pos4]) - s2[pos2];
    				pos3 = query2(r + 1, pos2 - 1), pos4 = query2(pos2 + 1, l - 1), res2 = s1[pos1] - min(s2[pos3], s2[pos4]);
    			}
    			printf("%lld
    ", max(res1, res2));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    多项式全家桶——Part.3 多项式求逆、除法、开根号
    多项式全家桶——Part.2 多项式位运算
    多项式全家桶——Part.1 多项式加减乘
    CSP2019总结
    jzoj6384. 【NOIP2019模拟2019.10.23】珂学家
    jzoj6377. 【NOIP2019模拟2019.10.05】幽曲[埋骨于弘川]
    jzoj6374. 【NOIP2019模拟2019.10.04】结界[生与死的境界]
    jzoj6370. 【NOIP2019模拟2019.9.28】基础 fake 练习题
    一个初学者的辛酸路程-基于Django写BBS项目
    一个初学者的辛酸路程-依旧Django
  • 原文地址:https://www.cnblogs.com/andysj/p/13986497.html
Copyright © 2020-2023  润新知