SDOI2017 Round1 簡要題解

咱們 TM 怎麼又要上文化課。。我 嗶嗶嗶嗶嗶嗶html

「SDOI2017」數字表格

題意

有 $T$ 組數據,求c++

$$ \prod_{i = 1}^{n} \prod_{j = 1}^{m} fib[\gcd(i, j)] $$git

$ 1 \leq n, m \leq 10 ^ 6, 1 \leq T \leq 1000 $優化

題解

又是一道莫比烏斯反演套路題。。ui

$$ \begin{aligned} &\prod_{i = 1}^{n} \prod_{j = 1}^{m} fib[\gcd(i, j)]\ &=\prod_{d = 1}^{n} fib[d]^{\sum_{i = 1}^n\sum_{j = 1}^n [(i, j) = d]} \end{aligned} $$spa

寫在冪次那裏很差看,咱們單獨提出來。。。debug

$$ \begin{aligned} & \sum_{i = 1}^n\sum_{j = 1}^n [(i, j) = d]\ &= \sum_{d | x} \mu(\frac x d) \lfloor \frac{n}{x} \rfloor \lfloor \frac{m}{x} \rfloor\ &= \sum_{i = 1} ^ {\lfloor \frac{n}{d} \rfloor} \mu(i) \lfloor \frac{n}{id} \rfloor \lfloor \frac{m}{id} \rfloor \end{aligned} $$code

咱們令 $T = id$ 那麼原式就變成htm

$$ \begin{aligned} &\prod_{d = 1}^{n} fib[d]^{\sum_{i = 1} ^ {\lfloor \frac{n}{d} \rfloor} \mu(i) \lfloor \frac{n}{id} \rfloor \lfloor \frac{m}{id} \rfloor}\ &= \prod_{T = 1}^n (\prod_{d | T} fib[d]^{\mu(\frac{T}{d} )})^{\lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T} \rfloor} \end{aligned} $$blog

預處理中間那個括號的內容,而後外面套整除分塊便可。

其實不預處理,套兩層整除分塊 $\mathcal LOJ$ 的機子能夠卡過 QAQ

複雜度是 $\mathcal O(n \log n + T \sqrt n \log n)$ 的。

代碼

#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), _end_ = (int)(r); i <= _end_; ++i)
#define Fordown(i, r, l) for(register int i = (r), _end_ = (int)(l); i >= _end_; --i)
#define Set(a, v) memset(a, v, sizeof(a))

using namespace std;

bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}

inline int read() {
    int x = 0, fh = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar() ) if (ch == '-') fh = -1;
    for (; isdigit(ch); ch = getchar() ) x = (x<<1) + (x<<3) + (ch ^ '0');
    return x * fh;
}

typedef long long ll;

int n, m;
const int N = 1e6 + 1e3;
ll mu[N], prime[N / 4], fib[N], ifib[N], cnt, g[N], ig[N];
bitset<N> is_prime;
const int Mod = 1e9 + 7, Pmod = Mod - 1;

ll fpm(ll x, ll power) {
    ll res = 1;
    for (; power; power >>= 1, (x *= x) %= Mod)
        if (power & 1) (res *= x) %= Mod;
    return res;
}

void Init(int maxn) {
    is_prime.set();
    is_prime[0] = is_prime[1] = false;
    int res; g[0] = ig[0] = g[1] = ifib[1] = mu[1] = fib[1] = 1;
    For (i, 2, maxn) {
        if (is_prime[i]) {
            prime[++cnt] = i;
            mu[i] = -1;
        }
        For (j, 1, cnt) {
            res = prime[j] * i;
            if (res > maxn) break ;
            is_prime[res] = false;
            if (i % prime[j]) mu[res] = -mu[i];
            else {mu[res] = 0; break ;}
        }
        g[i] = 1;
        fib[i] = fib[i - 1] + fib[i - 2];
        if (fib[i] >= Mod) fib[i] -= Mod;
        ifib[i] = fpm(fib[i], Mod - 2);
    }
    
    For (i, 1, maxn) {
    	for (register int j = i, t = 1; j <= maxn; j += i, ++ t)
    		if (mu[t] == 1) g[j] *= fib[i], g[j] = g[j] >= Mod ? g[j] % Mod : g[j];
    		else if (mu[t] == -1) g[j] *= ifib[i], g[j] = g[j] >= Mod ? g[j] % Mod : g[j];
    	(g[i] *= g[i - 1]) %= Mod;
    	ig[i] = fpm(g[i], Mod - 2);
    }
}

ll Calc() {
	cerr << "Calc: " << endl;
    ll res = 1; ll Nextd, n_, m_;
    if (n > m) swap(n, m);
    For(d, 1, n) {
        n_ = n / d; m_ = m / d;
        Nextd = min(n / n_, m / m_);
        (res *= fpm(g[Nextd] * ig[d - 1] % Mod, n_ * m_ % Pmod) ) %= Mod;
        d = Nextd;
    }
    return res;
}

void File() {
#ifdef zjp_shadow
	freopen ("2000.in", "r", stdin);
	freopen ("2000.out", "w", stdout);
#endif
}

int main() {
	File();
    Init((int)1e6);
    int cases = read();
    while (cases --) {
        n = read(); m = read();
        printf ("%lld\n", Calc() );
    }
    return 0;
}

「SDOI2017」樹點塗色

看我以前的 題解 就好啦。

彷佛說是一個套路題?染上沒有的顏色就是 access 的過程,而後套上線段樹維護就好啦。

「SDOI2017」序列計數

題意

求有多少個長度爲 $ n $ 的序列,至少有一個數是質數,序列中的數都是不超過 $ m $ 的正整數,並且這 $ n $ 個數的和是 $ p $ 的倍數。答案對於 $20170408$ 取模。

$ 1 \leq n \leq 10 ^ 9, 1 \leq m \leq 2 \times 10 ^ 7, 1 \leq p \leq 100 $。

題解

看到數據就知道是思博矩冪了,能夠作到 $\mathcal O(m + p^3 \log n)$ 。

其實這是個循環矩陣,無限自乘仍是循環的。咱們只須要維護其中一行就知道其它全部行了,那每次拿個向量搞搞得出一行就行啦。

這樣能夠作到 $\mathcal O(m + p^2 \log n)$ 。

其實那個過程本質上是循環卷積,可是和 $FFT$ 關於 $2^k$ 循環彷佛不太契合。

那麼這個多項式快速冪每次只能作到 $\mathcal O(m + p \log p \log n)$ 。

其實能夠利用 ln 變成加法,而後 exp 回去便可,作到 $\mathcal O(m + p \log p)$ 。

但因爲模數的鬼畜,不能用 NTT 利用 MTT 實現就好啦。。。

代碼

顯然個人作法是最暴力的矩冪啦 qwq

#include <bits/stdc++.h>

#define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl

using namespace std;

template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; }

inline int read() {
	int x(0), sgn(1); char ch(getchar());
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
	for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
	return x * sgn;
}

void File() {
#ifdef zjp_shadow
	freopen ("2002.in", "r", stdin);
	freopen ("2002.out", "w", stdout);
#endif
}

const int N = 2e7 + 1e3, M = 110, Mod = 20170408;

int n, m, p;

bitset<N> is_prime; int prime[N], plen;

void Linear_Sieve(int maxn) {
	is_prime.set();
	is_prime[0] = is_prime[1] = false;
	For (i, 2, maxn) {
		if (is_prime[i])
			prime[++ plen] = i; 
		For (j, 1, plen) {
			int res = prime[j] * i;
			if (res > maxn) break;
			is_prime[res] = false;
			if (!(i % prime[j])) break;
		}
	}
}

int ptot[M], tot[M]; 

struct Mat {

	int a[M][M];

	Mat() { Set(a, 0); }

	inline void Unit() {
		Rep (i, p) a[i][i] = 1;
	}

	inline Mat friend operator * (const Mat &lhs, const Mat &rhs) {
		Mat res;
		Rep (i, p) Rep (k, p) Rep (j, p)
			res.a[i][j] = (res.a[i][j] + 1ll * lhs.a[i][k] * rhs.a[k][j]) % Mod;
		return res;
	}

};

inline Mat fpm(Mat x, int power) {
	Mat res; res.Unit();
	for (; power; power >>= 1, x = x * x)
		if (power & 1) res = res * x;
	return res;
}

Mat f, trans;

int main () {

	File();

	n = read(); m = read(); p = read();

	Linear_Sieve(m);

	For (i, 1, m) {
		++ tot[i % p];
		if (is_prime[i]) ++ ptot[i % p];
	}

	Rep (i, p) Rep (j, p)
		trans.a[(i + j) % p][i] += tot[j];
	f.a[0][0] = 1; f = fpm(trans, n) * f;

	int ans = f.a[0][0];

	Rep (i, p) Rep (j, p) 
		trans.a[(i + j) % p][i] -= ptot[j];
	Set(f.a, 0); f.a[0][0] = 1; f = fpm(trans, n) * f;

	ans = (ans + Mod - f.a[0][0]) % Mod;
	printf ("%d\n", ans);

    return 0;

}

#「SDOI2017」新生舞會

題意

左右各有 $n$ 個點的二分圖, $a_{i, j}, b_{i, j}$ 爲 $i, j$ 匹配能獲得的兩個權值。

一個方案中有 $ n $ 對匹配,假設每組匹配的權值 $a_{i, j}$ 分別是 $ a'_1, a'_2, \ldots, a'n $, $b{i, j}$ 分別是 $ b'_1, b'_2, \ldots, b'_n $。令

求一個完美匹配,使得

$$ C = \frac{a'_1 + a'_2 + \cdots + a'_n}{b'_1 + b'_2 + \cdots + b'_n} $$

儘可能大。

題解

這 round1 模板題是真多。。。

直接分數規劃,二分 $C$ ,邊權就變成 $a_{i, j} - C \times b_{i, j}$ 。

那麼就是找一個完美匹配使得匹配的邊權和不小於 $0$ 。

而後用 KM 或者費用流跑最大權匹配就好了。

代碼

#include <bits/stdc++.h>

#define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl

using namespace std;

template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; }

inline int read() {
	int x(0), sgn(1); char ch(getchar());
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
	for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
	return x * sgn;
}

void File() {
#ifdef zjp_shadow
	freopen ("2003.in", "r", stdin);
	freopen ("2003.out", "w", stdout);
#endif
}

const int inf = 0x3f3f3f3f;

template<int Maxn, int Maxm>
struct MCMF {

	int Head[Maxn], Next[Maxm], to[Maxm], cap[Maxm], e; double val[Maxm];

	void Init() {
		e = 1; Set(Head, 0);
	}

	inline void add_edge(int u, int v, double cost, int flow) {
		to[++ e] = v; Next[e] = Head[u]; Head[u] = e;
		val[e] = cost; cap[e] = flow;
	}

	inline void Add(int u, int v, double cost, int flow) {
		add_edge(u, v, cost, flow); add_edge(v, u, -cost, 0);
	}

	int S, T;

	int pre[Maxn]; double dis[Maxn]; bitset<Maxn> inq;

	bool Spfa() {
		queue<int> Q; 
		For (i, 1, T) dis[i] = - 1e8;
		Set(pre, 0); inq.reset();

		Q.push(S); dis[S] = 1;
		while (!Q.empty()) {
			int u = Q.front(); Q.pop(); inq[u] = false;
			for (int i = Head[u], v = to[i]; i; v = to[i = Next[i]]) {
				if (cap[i] && chkmax(dis[v], dis[u] + val[i])) {
					pre[v] = i; if (!inq[v]) inq[v] = true, Q.push(v);
				}
			}
		}
		return pre[T];
	}

	double Run() {
		int sum_flow = 0; double sum_cost = 0;
		while (Spfa()) {
			int flow = inf;
			for (int u = T; u != S; u = to[pre[u] ^ 1]) chkmin(flow, cap[pre[u]]);
			for (int u = T; u != S; u = to[pre[u] ^ 1]) {
				cap[pre[u]] -= flow;
				cap[pre[u] ^ 1] += flow;
				sum_cost += val[pre[u]] * flow;
			}
			sum_flow += flow;
		}
		return sum_cost;
	}

};

const int N = 110;
const double eps = 1e-8;

MCMF<N * 2, N * N * 2> T;

int n; double A[N][N], B[N][N];

#define In(x) (x)
#define Out(x) ((x) + n)

inline bool check(double k) {
	T.Init();
	T.T = (T.S = Out(n) + 1) + 1;
	For (i, 1, n) {
		T.Add(T.S, In(i), 0, 1);
		T.Add(Out(i), T.T, 0, 1);
	}
	For (i, 1, n) For (j, 1, n)
		T.Add(In(i), Out(j), A[i][j] - k * B[i][j], 1);
	return T.Run() > 0;
}

int main () {

	File();

	n = read();

	For (i, 1, n) For (j, 1, n) A[i][j] = read();
	For (i, 1, n) For (j, 1, n) B[i][j] = read();

	double l = 0.0, r = 1e8;
	while (r - l > eps) {
		double mid = (l + r) / 2.0;
		if (check(mid)) l = mid; else r = mid;
	}
	printf ("%.6lf\n", l);

	return 0;

}

「SDOI2017」硬幣遊戲

題意

選出 $ n $ 個同窗, 每一個同窗猜一個長度爲 $ m $ 的序列,當某一個同窗猜的序列在硬幣序列中出現時,就再也不扔硬幣了,而且這個同窗勝利。爲了保證只有一個同窗勝利,同窗們猜的 $ n $ 個序列兩兩不一樣。

最後求出每一個同窗勝利的機率。

$ 1 \leq n, m \leq 300 $

題解

六道題裏惟一沒有那麼思博的題。。

暴力 ac自動機 + 高斯消元 是 $\mathcal O((nm)^3)$ 的,只有 $40$ 分。

考慮優化,顯然咱們最後要求的只有 $n$ 個變量的值,其餘變量都是毫無心義的。

那麼咱們只須要求出這些變量之間的相關方程便可。

咱們多設一個 $f_s$ 爲不匹配到其中任意一個同窗的機率,那麼咱們在當前串後面添加一個同窗 $i$ 的擁有的字符串 $S_i$ 就能對應到它的機率。

這個彷佛利用了一個結論,若是不匹配到 $n$ 個結束節點,停到任意一個點的機率彷佛是相同的。

可是這樣會把 $S_i$ 有個前綴和 $S_j$ 一個後綴是同樣的機率多算上去,咱們減掉就好了,這個出現的機率是 $2^{-l}$ ,$l$ 爲這個前綴的長度。

利用 KMP 實現就能夠作到 $\mathcal O(n^2(n + m))$ 啦。

代碼

我懶,用的暴力匹配。。也過啦。。

#include <bits/stdc++.h>

#define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl

using namespace std;

template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; }

inline int read() {
	int x(0), sgn(1); char ch(getchar());
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
	for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
	return x * sgn;
}

void File() {
#ifndef ONLINE_JUDGE
	freopen ("2004.in", "r", stdin);
	freopen ("2004.out", "w", stdout);
#endif
}

const int N = 310;

double G[N][N];

void Gauss(int n) {
	For (i, 1, n) {
		For (j, i + 1, n) if (fabs(G[j][i]) > fabs(G[i][i])) swap(G[i], G[j]);
        if (!G[i][i]) continue;
		Fordown (j, n + 1, i) G[i][j] /= G[i][i];
		For (j, i + 1, n) Fordown (k, n + 1, i) G[j][k] -= G[j][i] * G[i][k];
	}
	Fordown (i, n, 1) {
		For (j, 1, i - 1)
			G[j][n + 1] -= G[j][i] * G[i][n + 1], G[j][i] = 0;
	}
}

int n, m; double inv[N];

char str[N][N];

int main() {

    File();

    n = read(); m = read();

    For (i, 1, n) scanf ("%s", str[i] + 1);

    inv[0] = 1.0;
    For (i, 1, m) inv[i] = inv[i - 1] / 2.0;

    For (i, 1, n) {
        G[i][i] = 1.0; G[i][n + 1] = - 1.0;
        For (j, 1, n) {
            For (p, 2, m) {
                int len = 1;
                while (p + len - 1 <= m && str[i][len] == str[j][p + len - 1]) ++ len;
                if (p + len == m + 2) G[i][j] += inv[p - 1];
            }
        }
    }

    For (i, 1, n) G[n + 1][i] = 1.0; G[n + 1][n + 2] = 1.0;

    Gauss(n + 1);

    For (i, 1, n)
        printf ("%.10lf\n", G[i][n + 2]);

    return 0;

}

「SDOI2017」相關分析

題意

一個序列,每一個元素是一個點 $(x_i, y_i)$ 。

有 $m$ 個操做,共有三種:

  • $\texttt{1 L R}:$ 求 $[L, R]$ 的迴歸直線的斜率。

  • $\texttt{2 L R S T}:$ 把 $i \in [L, R]$ $x_i$ 加上 $S$ ,$y_i$ 加上 $T$ 。

  • $\texttt{2 L R S T}:$ 把 $i \in [L, R]$ $x_i$ 變成 $S + i$ ,$y_i$ 變成 $T + i$ 。

$ 1 \leq n, m \leq 10 ^ 5 $

題解

昨天才講的迴歸直線。。今天就用上啦QAQ

$$ \hat{a} = \frac{\sum\limits_{i = L} ^ R (x_i - \bar{x})(y_i - \bar{y})}{\sum\limits_{i = L} ^ R (x_i - \bar{x}) ^ 2} $$

這個數學書上經常用另一種化簡的方式。。

令 $n = R - L + 1$ 即區間長度。

$$ \hat{a} = \frac{(\sum\limits_{i = L} ^ R x_i y_i) - n\bar{x}\bar{y}}{(\sum\limits_{i = L} ^ R x_i^2) - n \bar{x}^2} $$

而後維護區間 $x, y, xy, x^2$ 的和就好了。

代碼

#include <bits/stdc++.h>

#define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl

using namespace std;

template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; }

inline int read() {
	int x(0), sgn(1); char ch(getchar());
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
	for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
	return x * sgn;
}

void File() {
#ifdef zjp_shadow
	freopen ("2005.in", "r", stdin);
	freopen ("2005.out", "w", stdout);
#endif
}

const int N = 1e5 + 1e3;

using ll = double;

ll pre1(ll x) {
	return x * (x + 1) / 2;
}

ll pre2(ll x) {
	return x * (x + 1) * (2 * x + 1) / 6;
}

#define ls o << 1
#define rs o << 1 | 1
#define mid ((l + r) >> 1)
#define lson ls, l, mid
#define rson rs, mid + 1, r

template<int Maxn>
struct Segment_Tree {

	ll sumxy[Maxn], sumx[Maxn], sumy[Maxn], sumxx[Maxn];

	int tag[Maxn], S[Maxn], T[Maxn];

	inline void modify(int o, int l, int r, int opt, int sv, int tv) {
		int len = r - l + 1; 
		chkmax(tag[o], opt);
		if (opt == 2) {
			sumxy[o] += sv * sumy[o] + tv * sumx[o] + 1ll * len * sv * tv;
			sumxx[o] += 2 * sv * sumx[o] + 1ll * len * sv * sv;
			sumx[o] += 1ll * sv * len;
			sumy[o] += 1ll * tv * len;
			S[o] += sv; T[o] += tv;
		} else {
			sv += l; tv += l;
			sumxy[o] = 1ll * len * sv * tv + pre1(len - 1) * (sv + tv) + pre2(len - 1);
			sumxx[o] = 1ll * len * sv * sv + 2 * pre1(len - 1) * sv + pre2(len - 1);
			sumx[o] = 1ll * len * sv + pre1(len - 1);
			sumy[o] = 1ll * len * tv + pre1(len - 1);
			S[o] = sv - l; T[o] = tv - l;
		}
	}

	inline void push_down(int o, int l, int r) {
		if (tag[o]) {
			modify(lson, tag[o], S[o], T[o]);
			modify(rson, tag[o], S[o], T[o]);
			tag[o] = S[o] = T[o] = 0;
		}
	}

	inline void push_up(int o) {
		sumxy[o] = sumxy[ls] + sumxy[rs];
		sumxx[o] = sumxx[ls] + sumxx[rs];
		sumx[o] = sumx[ls] + sumx[rs];
		sumy[o] = sumy[ls] + sumy[rs];
	}

	void Update(int o, int l, int r, int opt, int ul, int ur, int sv, int tv) {
		if (ul <= l && r <= ur) {
			modify(o, l, r, opt, sv, tv); return;
		}
		push_down(o, l, r);
		if (ul <= mid) Update(lson, opt, ul, ur, sv, tv);
		if (ur > mid) Update(rson, opt, ul, ur, sv, tv);
		push_up(o);
	}

	ll Query(int o, int l, int r, int ql, int qr, ll *sum) {
		if (ql <= l && r <= qr) return sum[o];
		push_down(o, l, r); ll res = 0;
		if (ql <= mid) res += Query(lson, ql, qr, sum);
		if (qr > mid) res += Query(rson, ql, qr, sum);
		push_up(o); return res;
	}

	void Build(int o, int l, int r, int *x, int *y) {
		if (l == r) {
			sumxy[o] = 1ll * x[l] * y[r];
			sumxx[o] = 1ll * x[l] * x[r];
			sumx[o] = x[l]; sumy[o] = y[r];
			return;
		}
		Build(lson, x, y); Build(rson, x, y); push_up(o);
	}

};

Segment_Tree<N << 2> T;

int n, m, x[N], y[N];

#define root 1, 1, n

int main () {

	File();

	n = read(); m = read();

	For (i, 1, n) x[i] = read();
	For (i, 1, n) y[i] = read();

	T.Build(root, x, y);

	while (m --) {
		int opt = read(), l = read(), r = read();
		if (opt == 1) {
			ll sumxy = T.Query(root, l, r, T.sumxy),
			   sumxx = T.Query(root, l, r, T.sumxx),
			   sumx = T.Query(root, l, r, T.sumx),
			   sumy = T.Query(root, l, r, T.sumy), len = r - l + 1;
			double averx = 1.0 * sumx / len, avery = 1.0 * sumy / len,
				   k = 1.0 * (sumxy - len * averx * avery) / (sumxx - len * averx * averx);
			printf ("%.6lf\n", k);
		} else {
			int sv = read(), tv = read();
			T.Update(root, opt, l, r, sv, tv);
		}
	}

	return 0;

}
相關文章
相關標籤/搜索