zoukankan      html  css  js  c++  java
  • loj6435

    题意

    log

    做法一

    结论1((jin[1,i))dis(i,j))是单调不升的

    显然

    考虑(i)向左那些点走的方法,(dis(i,j)=1)的这些点显然是直接与(i)相连的
    然后发现距离为(2)的那些点方法有点奇怪,既可以(i)向左走两步,也可以(i)向右走一步再向左走一步
    对走的方法找一找结论

    显然的,向右走只有可能是一开始,一旦向左走就不会回头了
    结论2:不会存在向右超过一步的情况

    证明:
    考虑向右走的最后一步,然后向左走,若不走到(i)左边显然没有意义
    若走到(i)左边了,显然其也是与(i)直接相连的,故可以一开始直接走到那个点,再向左走

    结论3(dis(i,j)le 2(jin[1,i)))的充要条件为距离([l_i,n])某一点距离不超过(1)
    推论(dis(i,j)le k(jin[1,i)))的充要条件为距离([l_i,n])某一点距离不超过(k-1)

    然后自然的倍增来做

    做法二

    这个就比较简单了,没那么多细节
    直接维护对于每个(i)([1,i))走进([i,n])的最短路径
    那怎么维护这个东西呢。令(mn_i=min{l_j|jin[i,n]})
    假设已经得到了([1,mn_i))走进([mn_i,n])的最短路径,则([1,i))走到([i,n])的最短路径只要在其基础上([1,i))(1)即可

    正确性:
    一开始([1,mn_i))只能走进([mn_i,i)),因为如果能走进([i,n]),则(mn_i)会左移

    然后这个主席树维护即可

    那么查询(l,r,x)时,就查询([l_x,n])维护的东西

    code(做法一)

    这题实现来讲有些细节,拉一份这里的代码,这篇题解也写的挺好的

    #include <bits/stdc++.h>
    #define N 300005
    #define LN 20
    #define ID isdigit(c = *next++)
    
    struct Istream {
    	char *next, buf[20030731];
    	void init(FILE *f = stdin) {fread(buf, 1, sizeof buf, f); next = buf;}
    	Istream & operator >> (int &x) {
    		int c; x = 0;
    		for (; !ID; ) if (!~c) return *this;
    		for (x = c & 15; ID; x = x * 10 + (c & 15)) if (!~c) break;
    		return *this;
    	}
    } cin;
    
    struct Ostream {
    	char *next, buf[20030731], _buf[34];
    	Ostream () {next = buf;}
    	void flush(FILE *f = stdout) {fwrite(buf, 1, next - buf, f); next = buf;}
    	Ostream & operator << (long long x) {
    		if (!x) return put(48), *this;
    		int i;
    		for (i = 0; x; x /= 10) _buf[++i] = x % 10 | 48;
    		for (; i; --i) put(_buf[i]);
    		return *this;
    	}
    	Ostream & operator << (char c) {return put(c), *this;}
    	void put(char c) {*next++ = c;}
    } cout;
    
    typedef long long ll;
    
    int n, q;
    int l[N];
    int P[LN][N], *p = *P;
    ll s[LN][N];
    
    inline void down(int &x, const int y) {x > y ? x = y : 0;}
    
    ll solve(int u, int v) {
    	if (u >= l[v]) return std::max(v - u, 0);
    	int i, cur = 1; ll res = v - l[v]; v = l[v];
    	for (i = LN - 1; i >= 0; --i)
    		if (P[i][v] > u) {
    			res += s[i][v] + (ll)(v - P[i][v]) * cur;
    			cur += 1 << i; v = P[i][v];
    		}
    	return res + (v - u) * (cur + 1);
    }
    
    int main() {
    	int i, u, v; ll num, den, d;
    	cin.init();
    	cin >> n;
    	for (i = 2; i <= n; ++i) cin >> l[i]; p[n + 1] = INT_MAX;
    	for (i = n; i > 1; --i) {
    		p[i] = std::min(l[i], p[i + 1]);
    		s[0][i] = i - p[i];
    	}
    	for (v = 2; v <= n; ++v)
    		for (i = 0; i < LN - 1; ++i) {
    			P[i + 1][v] = P[i][P[i][v]];
    			s[i + 1][v] = s[i][v] + s[i][P[i][v]] + ((ll)(P[i][v] - P[i + 1][v]) << i);
    		}
    	for (cin >> q; q; --q) {
    		cin >> u >> v >> i;
    		num = solve(u, i) - solve(v + 1, i);
    		d = std::__gcd(num, den = v - u + 1);
    		cout << num / d << '/' << den / d << '
    ';
    	}
    	cout.flush();
    	return 0;
    }
    
    
  • 相关阅读:
    MySQL之----在java编程加强知识点
    走进windows编程的世界-----入门篇
    对Java、C#转学swift的提醒:学习swift首先要突破心理障碍。
    LeetCode--N-Queens
    美国人与欧洲人为什么都吃转基因食品?
    hdu1290
    OS 中文斜体 Italic Font Chinese
    为什么那些每三年跳一次槽的人越跳越好?
    [博弈] hdu 3683 Gomoku
    HDU 5358 First One(枚举)
  • 原文地址:https://www.cnblogs.com/Grice/p/13046677.html
Copyright © 2011-2022 走看看