zoukankan      html  css  js  c++  java
  • 【bzoj4889】[Tjoi2017]不勤劳的图书管理员 树状数组+分块+二分

    题目描述(转自洛谷)

    加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员。他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生这两本书页数的和的厌烦度。现在有n本被打乱顺序的书,在接下来m天中每天都会因为读者的阅览导致书籍顺序改变位置。因为小豆被要求在接下来的m天中至少要整理一次图书。小豆想知道,如果他前i天不去整理,第i天他的厌烦度是多少,这样他好选择厌烦度最小的那天去整理。

    输入

    第一行会有两个数,n,m分别表示有n本书,m天

    接下来n行,每行两个数,ai和vi,分别表示第i本书本来应该放在ai的位置,这本书有vi页,保证不会有放置同一个位置的书

    接下来m行,每行两个数,xj和yj,表示在第j天的第xj本书会和第yj本书会因为读者阅读交换位置

    n、m<=50000

    输出

    一共m行,每行一个数,第i行表示前i天不去整理,第i天小豆的厌烦度,因为这个数可能很大,所以将结果模10^9 +7后输出

    样例输入

    5 5
    1 1
    2 2
    3 3
    4 4
    5 5
    1 5
    1 5
    2 4
    5 3
    1 3

    样例输出

    42
    0
    18
    28
    48


    题解

    树状数组+分块+二分

    一开始看到n、m<=50000写了个区间线段树套权值线段树,结果写了垃圾回收却仍然MLE+RE(也许区间线段树套SBT可能不会MLE或RE,但TLE的事也不好说)

    所以不能过分相信nlog^2n数据结构,分块才是王道。

    那么本题就和 bzoj3343 相似。

    先用树状数组预处理出一开始的答案(正着扫一遍,反过来再扫一遍)。

    然后考虑:交换两个数,只对它们中间的数产生影响。所以只需要统计出它们中间有多少个比x大的,比x小的,比y大的,比y小的。

    考虑它们原来对答案的贡献,和交换后对答案的贡献,把ans加加减减就好了。

    我们可以分块实现这个过程,对于每个块把该块的数排序,并维护前缀和。查询时,对于整块可以二分查找,零碎的部分暴力完成。

    最后再判断x和y是否会产生逆序对,并更新答案即可。

    注意特判x和y在同一个块内的情况。

    另外,本题的ans不用在计算的过程中取模,直接使用long long类型记录,最后输出时取个模就行了。

    时间复杂度$O(nsqrt nlog n)$

    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    #define N 50010
    using namespace std;
    typedef long long ll;
    struct data
    {
    	int p;
    	ll w;
    	bool operator<(const data a)const {return p < a.p;}
    }a[N];
    struct block
    {
    	data val[250];
    	int lp , rp;
    	ll sum[250];
    	void build()
    	{
    		int i;
    		for(i = 1 ; i <= rp - lp + 1 ; i ++ ) val[i] = a[i + lp - 1];
    		sort(val + 1 , val + rp - lp + 2);
    		for(i = 1 ; i <= rp - lp + 1 ; i ++ ) sum[i] = sum[i - 1] + val[i].w;
    	}
    	ll qsmall(int pos)
    	{
    		int l = 1 , r = rp - lp + 1 , mid , ans = l - 1;
    		while(l <= r)
    		{
    			mid = (l + r) >> 1;
    			if(val[mid] < a[pos]) ans = mid , l = mid + 1;
    			else r = mid - 1;
    		}
    		return ans * a[pos].w + sum[ans];
    	}
    	ll qbig(int pos)
    	{
    		int l = 1 , r = rp - lp + 1 , mid , ans = r + 1;
    		while(l <= r)
    		{
    			mid = (l + r) >> 1;
    			if(a[pos] < val[mid]) ans = mid , r = mid - 1;
    			else l = mid + 1;
    		}
    		return (rp - lp - ans + 2) * a[pos].w + sum[rp - lp + 1] - sum[ans - 1];
    	}
    }b[250];
    int bl[N] , f[N] , g[N] , n;
    void add1(int x , ll a) {int i; for(i = x ; i ; i -= i & -i) f[i] += a;}
    ll query1(int x) {int i; ll ans = 0; for(i = x ; i <= n ; i += i & -i) ans += f[i]; return ans;}
    void add2(int x , ll a) {int i; for(i = x ; i <= n ; i += i & -i) g[i] += a;}
    ll query2(int x) {int i; ll ans = 0; for(i = x ; i ; i -= i & -i) ans += g[i]; return ans;}
    int main()
    {
    	int m , i , si , x , y;
    	ll ans = 0 , t1 , t2 , t3 , t4;
    	scanf("%d%d" , &n , &m) , si = (int)sqrt(n);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%d%lld" , &a[i].p , &a[i].w) , bl[i] = (i - 1) / si + 1;
    	for(i = 1 ; i <= bl[n] ; i ++ ) b[i].lp = (i - 1) * si + 1 , b[i].rp = min(i * si , n) , b[i].build();
    	for(i = 1 ; i <= n ; i ++ ) ans += query1(a[i].p + 1) , add1(a[i].p , a[i].w);
    	for(i = n ; i >= 1 ; i -- ) ans += query2(a[i].p - 1) , add2(a[i].p , a[i].w);
    	while(m -- )
    	{
    		scanf("%d%d" , &x , &y);
    		if(x == y) {printf("%lld
    " , ans % 1000000007); continue;}
    		if(x > y) swap(x , y);
    		t1 = t2 = t3 = t4 = 0;
    		if(y - x > 1)
    		{
    			if(bl[x] == bl[y])
    				for(i = x + 1 ; i < y ; i ++ )
    					t1 += (a[i] < a[x]) * (a[i].w  + a[x].w), t2 += (a[x] < a[i]) * (a[i].w + a[x].w) , t3 += (a[i] < a[y]) * (a[i].w + a[y].w) , t4 += (a[y] < a[i]) * (a[i].w + a[y].w);
    			else
    			{
    				for(i = bl[x] + 1 ; i < bl[y] ; i ++ )
    					t1 += b[i].qsmall(x) , t2 += b[i].qbig(x) , t3 += b[i].qsmall(y) , t4 += b[i].qbig(y);
    				for(i = x + 1 ; i <= b[bl[x]].rp ; i ++ )
    					t1 += (a[i] < a[x]) * (a[i].w  + a[x].w), t2 += (a[x] < a[i]) * (a[i].w + a[x].w) , t3 += (a[i] < a[y]) * (a[i].w + a[y].w) , t4 += (a[y] < a[i]) * (a[i].w + a[y].w);
    				for(i = b[bl[y]].lp ; i < y ; i ++ )
    					t1 += (a[i] < a[x]) * (a[i].w  + a[x].w), t2 += (a[x] < a[i]) * (a[i].w + a[x].w) , t3 += (a[i] < a[y]) * (a[i].w + a[y].w) , t4 += (a[y] < a[i]) * (a[i].w + a[y].w);
    			}
    			ans = ans - t1 + t2 + t3 - t4;
    		}
    		if(a[x] < a[y]) ans += a[x].w + a[y].w;
    		else ans -= a[x].w + a[y].w;
    		printf("%lld
    " , ans % 1000000007);
    		swap(a[x] , a[y]);
    		b[bl[x]].build() , b[bl[y]].build();
    	}
    	return 0;
    }
    
  • 相关阅读:
    TCP校验和
    Python8 数据库基础
    Python7 TCPIP协议与抓包
    Python6 线程与进程、网络编程、生成器与迭代器、协程、异步IO
    python2 变量与数据类型
    Python10 前端基础与爬虫
    Python11 Scrapy框架基础
    python3 函数、运算符与数据类型的常用方法
    Python9 数据库进阶
    python1 简介
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7124586.html
Copyright © 2011-2022 走看看