zoukankan      html  css  js  c++  java
  • 题解【洛谷P2221】[HAOI2012]高速公路

    题面

    我们需要一棵支持区间加、区间询问所有子区间和的线段树。

    对于询问,假设询问区间是 ([l,r]),答案即为:

    [dfrac{sumlimits_{i=l}^rsumlimits_{j=i}^r dis_{i,j}}{inom{r-l+1}{2}} ]

    分母可以直接 (mathcal{O}(1)) 算;

    对于分子,我们发现点之间的距离不好用线段树维护,于是我们把边转成点,然后考虑计算每一条边对答案的贡献:

    [egin{aligned}sum_{i=l}^r v_i(r-i+1)(i-l+1) &= sumlimits_{i=l}^r v_i(ri-lr+r-i^2+il-i+i-l+1) \ &= sumlimits_{i=l}^r -i^2v_i+iv_i(r+l)+v_i(-lr+r-l+1)end{aligned}]

    (s_1=sum v_i)(s_2=sum iv_i)(s_3=sum i^2v_i)

    答案即为:

    [egin{aligned} -s3+s_2(r+l)+s_1(-lr+r-l+1)end{aligned} ]

    可以开 (3) 棵线段树解决。

    然后考虑怎么修改。

    (s_1):直接区间修改即可。

    (s_2)(sum i(v_i+k)=sum iv_i+ik),可以维护一个前缀和 (s_4) 记录 (sum i)

    (s_3)(sum i^2(v_i+k)=sum i^2v_i+i^2k),维护一个前缀和 (s_5) 记录 (sum i^2)

    推荐练习:[SDOI2017]相关分析

    代码:

    #include <bits/stdc++.h>
    #define DEBUG fprintf(stderr, "Passing [%s] line %d
    ", __FUNCTION__, __LINE__)
    #define File(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout)
    #define int long long
    
    using namespace std;
    
    typedef long long LL;
    typedef pair <int, int> PII;
    typedef pair <int, PII> PIII;
    
    template <typename T>
    inline T gi()
    {
    	T f = 1, x = 0; char c = getchar();
    	while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
    	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    	return f * x;
    }
    
    const int INF = 0x3f3f3f3f, N = 100003, M = N << 1;
    
    int n, m;
    LL sum[4][N << 2], lz[4][N << 2];
    LL pr[3][N << 2];
    
    inline int ls(int p) {return p << 1;}
    inline int rs(int p) {return p << 1 | 1;}
    
    inline void pushup(int p)
    {
    	for (int i = 1; i <= 3; i+=1) sum[i][p] = sum[i][ls(p)] + sum[i][rs(p)];
    }
    
    inline void mark(int l, int r, int val, int p)
    {
    	sum[1][p] += 1ll * val * (r - l + 1),
    		sum[2][p] += 1ll * val * (pr[1][r] - pr[1][l - 1]),
    		sum[3][p] += 1ll * val * (pr[2][r] - pr[2][l - 1]);
    	lz[1][p] += val, lz[2][p] += val, lz[3][p] += val;
    }
    
    inline void pushdown(int l, int r, int p)
    {
    	int mid = (l + r) >> 1;
    	if (lz[1][p])
    	{
    		sum[1][ls(p)] += 1ll * lz[1][p] * (mid - l + 1),
    			sum[1][rs(p)] += 1ll * lz[1][p] * (r - mid);
    		lz[1][ls(p)] += lz[1][p],
    			lz[1][rs(p)] += lz[1][p];
    		lz[1][p] = 0;
    	}
    	if (lz[2][p])
    	{
    		sum[2][ls(p)] += 1ll * lz[2][p] * (pr[1][mid] - pr[1][l - 1]),
    			sum[2][rs(p)] += 1ll * lz[2][p] * (pr[1][r] - pr[1][mid]);
    		lz[2][ls(p)] += lz[2][p],
    			lz[2][rs(p)] += lz[2][p];
    		lz[2][p] = 0;
    	}
    	if (lz[3][p])
    	{
    		sum[3][ls(p)] += 1ll * lz[3][p] * (pr[2][mid] - pr[2][l - 1]),
    			sum[3][rs(p)] += 1ll * lz[3][p] * (pr[2][r] - pr[2][mid]);
    		lz[3][ls(p)] += lz[3][p],
    			lz[3][rs(p)] += lz[3][p];
    		lz[3][p] = 0;
    	}
    }
    
    void modify(int ql, int qr, int val, int l, int r, int p)
    {
    	if (ql <= l && r <= qr)
    	{
    		mark(l, r, val, p);
    		return;
    	}
    	pushdown(l, r, p);
    	int mid = (l + r) >> 1;
    	if (ql <= mid) modify(ql, qr, val, l, mid, ls(p));
    	if (qr > mid) modify(ql, qr, val, mid + 1, r, rs(p));
    	pushup(p);
    }
    
    LL getans(int id, int ql, int qr, int l, int r, int p)
    {
    	if (ql <= l && r <= qr) return sum[id][p];
    	pushdown(l, r, p);
    	int mid = (l + r) >> 1;
    	LL sum = 0;
    	if (ql <= mid) sum += getans(id, ql, qr, l, mid, ls(p));
    	if (qr > mid) sum += getans(id, ql, qr, mid + 1, r, rs(p));
    	return sum;
    }
    
    inline LL query(int l, int r)
    {
    	LL s1 = getans(1, l, r, 1, n - 1, 1), s2 = getans(2, l, r, 1, n - 1, 1), s3 = getans(3, l, r, 1, n - 1, 1);
    	return s2 * (l + r) + s1 * (r + 1 - l - l * r) - s3;
    }
    
    signed main()
    {
    	//File("");
    	n = gi <int> (), m = gi <int> ();
    	for (int i = 1; i <= n; i+=1)
    		pr[1][i] = pr[1][i - 1] + i, pr[2][i] = pr[2][i - 1] + 1ll * i * i;
    	while (m--)
    	{
    		char op[3];
    		scanf("%s", op);
    		int l = gi <int> (), r = gi <int> () - 1, v;
    		if (op[0] == 'C')
    		{
    			v = gi <int> ();
    			modify(l, r, v, 1, n - 1, 1);
    		}
    		else
    		{
    			if (l > r) {puts("0/1"); continue;}
    			LL len = 1ll * (r - l + 1) * (r - l + 2) / 2;
    			LL ans = query(l, r);
    			LL G = __gcd(ans, len);
    			ans /= G, len /= G;
    			printf("%lld/%lld
    ", ans, len);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    了解 NoSQL 的必读资料
    关于什么时候用assert(断言)的思考
    这次见到了一些大侠
    NetBeans 时事通讯(刊号 # 87 Jan 12, 2010)
    动态链接库dll,静态链接库lib, 导入库lib
    新女性十得 写得了代码,查得出异常
    记录系统乱谈
    新女性十得 写得了代码,查得出异常
    fullpage.js禁止滚动
    RunningMapReduceExampleTFIDF hadoopclusternet This document describes how to run the TFIDF MapReduce example against ascii books. This project is for those who wants to experiment hadoop as a skunkworks in a small cluster (110 nodes) Google Pro
  • 原文地址:https://www.cnblogs.com/xsl19/p/13620010.html
Copyright © 2011-2022 走看看