bzoj 2038

多校补不动的某人又来点技能树了。。

一直以为莫队是个数据结构,现在才知道,原来是一个算法。。

它是一个用来做离线询问的算法,使用分块的思想降低了时间复杂度。要使用它,还必须快速的完成当前状态到下个状态的转换

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
int n, m, last_l = 1, last_r = 0;
ll ans, p;
int color[50010], block[50010];
ll sum[50010];

struct os{
    ll part, l, r, nume, deno;//nume指分子,deno指分母
}q[50010];

bool cmp1(os xx, os yy){
    if (block[xx. l] < block[yy. l])
		return true;
    if (block[xx. l] > block[yy. l])
		return false;
    return xx. r < yy. r;
}
bool cmp2(os xx, os yy){
	return xx. part < yy. part;
}

inline ll gcd(ll x, ll y){
    if (! y) 
		return x;
    return gcd(y, x % y);
}
int main(){
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i ++) 
		scanf("%d", &color[i]);
    block[0] = sqrt(n);
    for (int i = 1; i <= n; i ++)
    	block[i] = (i - 1) / block[0] + 1;
    for (int i = 1; i <= m; i ++){
    	scanf("%d %d", &q[i]. l, &q[i]. r),
    	q[i]. part = i;
	}
    sort(q + 1, q + m + 1, cmp1);   

    for (int i = 1; i <= m; i ++){
        q[i]. deno = (q[i]. r - q[i]. l + 1) * (q[i]. r - q[i]. l);
        if (last_r < q[i]. r){
            for (int j = last_r + 1; j <= q[i]. r; j ++){
	            ans += ((sum[color[j]] << 1) + 1);
	            sum[color[j]] ++;
        	}
        }
        if (last_r > q[i]. r){
            for (int j = last_r; j > q[i]. r; j --){
	            ans -= ((sum[color[j]] << 1) - 1);
	            sum[color[j]] --;
	        }
        }
        if (last_l > q[i]. l){
            for (int j = last_l - 1; j >= q[i]. l; j --){
	            ans += ((sum[color[j]] << 1) + 1);
	            sum[color[j]] ++;
	        }
        }
        if (last_l < q[i]. l){
            for (int j = last_l; j <q[i]. l; j ++){
	            ans -= ((sum[color[j]] << 1) - 1);
	            sum[color[j]] --;
	        }
        }
        q[i]. nume = ans - (q[i]. r - q[i]. l + 1);
        last_l = q[i]. l;
        last_r = q[i]. r;
    }
    sort(q + 1, q + m + 1, cmp2);
    for (int i = 1; i <= m; i ++){
        if (! q[i]. nume){
			printf("0/1\n");
			continue;
		}
        p = gcd(q[i]. nume, q[i]. deno);
        printf("%lld/%lld\n", q[i]. nume / p, q[i]. deno / p);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38759433/article/details/81771893
今日推荐