1. 程式人生 > >【LOJ2322】「清華集訓 2017」Hello world!

【LOJ2322】「清華集訓 2017」Hello world!

【題目連結】

【思路要點】

  • 一個 1 0 13 10^{13} 以內的數開根 6
    6
    次後一定會變成 1 1 ,因此有效的修改次數不會超過 6 N
    6N
  • 設定一個閾值 α \alpha ,若 k
    α k≥\alpha
    ,則暴力進行詢問或修改,藉助長鏈剖分求 k k 級祖先,單次操作時間複雜度為 O ( N α ) O(\frac{N}{\alpha})
  • 考慮 k < α k<\alpha 的修改,用並查集維護每個點向上 k k 的整數倍步第一個能夠到達的非 1 1 的位置,再進行修改,就可以保證找到的位置上的修改有效。並查集大小為 O ( N α ) O(N\alpha)
  • 考慮 k < α k<\alpha 的詢問,用 α \alpha 棵樹狀陣列維護子樹和即可快速查詢。
  • 時間複雜度 O ( Q N α + 6 N L o g N α ) O(\frac{Q*N}{\alpha}+6NLogN*\alpha)

【程式碼】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int MAXLOG = 18;
const int limit = 25;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct BinaryIndexTree {
	int n; ll a[MAXN];
	void init(int x) {
		n = x;
		memset(a, 0, sizeof(a));
	}
	void modify(int x, ll d) {
		for (int i = x; i <= n; i += i & -i)
			a[i] += d;
	}
	ll query(int x) {
		ll ans = 0;
		for (int i = x; i >= 1; i -= i & -i)
			ans += a[i];
		return ans;
	}
} BIT[limit];
int n, m, highbit[MAXN]; ll val[MAXN];
int depth[MAXN], down[MAXN], son[MAXN], up[MAXN];
int f[MAXN][limit], father[MAXN][MAXLOG]; bool vis[MAXN];
int timer[limit], dfn[MAXN][limit], rit[MAXN][limit];
vector <int> a[MAXN], lst[MAXN][2];
void dfs(int pos, int fa) {
	depth[pos] = depth[fa] + 1;
	father[pos][0] = fa;
	for (int i = 1; i < MAXLOG; i++)
		father[pos][i] = father[father[pos][i - 1]][i - 1];
	for (unsigned i = 0; i < a[pos].size(); i++)
		if (a[pos][i] != fa) {
			dfs(a[pos][i], pos);
			if (down[a[pos][i]] > down[pos]) {
				down[pos] = down[a[pos][i]];
				son[pos] = a[pos][i];
			}
		}
	down[pos]++;
}
void efs(int pos, int fa, int from) {
	up[pos] = from;
	if (from == pos) {
		for (int i = pos; i; i = son[i])
			lst[pos][1].push_back(i);
		for (int i = pos; i; i = father[i][0])
			lst[pos][0].push_back(i);
	}
	if (son[pos]) efs(son[pos], pos, from);
	for (unsigned i = 0; i < a[pos].size(); i++)
		if (a[pos][i] != fa && a[pos][i] != son[pos]) efs(a[pos][i], pos, a[pos][i]);
}
int lca(int x, int y) {
	if (depth[x] < depth[y]) swap(x, y);
	for (int i = MAXLOG - 1; i >= 0; i--)
		if (depth[father[x][i]] >= depth[y]) x = father[x][i];
	if (x == y) return x;
	for (int i = MAXLOG - 1; i >= 0; i--)
		if (father[x][i] != father[y][i]) {
			x = father[x][i];
			y = father[y][i];
		}
	return father[x][0];
}
int ancestor(int x, int k) {
	if (k == 0) return x;
	if (k >= depth[x]) return 0;
	int tmp = highbit[k]; k -= 1 << tmp;
	x = father[x][tmp];
	int delta = depth[x] - depth[up[x]] - k;
	if (delta >= 0) return lst[up[x]][1][delta];
	else return lst[up[x]][0][-delta];
}
int findnxt(int x, int d) {
	if (f[x][d] == x) return x;
	else return f[x][d] = findnxt(f[x][d], d);
}
void modify(int pos) {
	if (vis[pos] && val[pos] == 1) return;
	ll delta = val[pos]; vis[pos] = true;
	val[pos] = sqrt(val[pos]);
	delta = val[pos] - delta;
	if (val[pos] == 1) {
		for (int i = 1, now = father[pos][0]; i < limit; i++, now = father[now][0])
			if (now) f[findnxt(pos, i)][i] = findnxt(now, i);
	}
	for (int i = 1; i < limit; i++) {
		BIT[i].modify(dfn[pos][i], delta);
		BIT[i].modify(rit[pos][i] + 1, -delta);
	}
}
void label(int pos, int fa, int k) {
	int now = depth[pos] % k;
	dfn[pos][k] = ++timer[now];
	for (unsigned i = 0; i < a[pos].size(); i++)
		if (a[pos][i] != fa) label(a[pos][i], pos, k);
	rit[pos][k] = timer[now];
}
int main() {
	read(n);
	for (int i = 1; i <= n; i++)
		read(val[i]);
	for (int i = 1; i <= n - 1; i++) {
		int x, y; read(x), read(y);
		a[x].push_back(y);
		a[y].push_back(x);
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j < limit; j++)
			f[i][j] = i;
		highbit[i] = highbit[i - 1];
		if (1 << (highbit[i] + 1) == i) highbit[i]++;
	}
	dfs(1, 0);
	efs(1, 0, 1);
	for (int j = 1; j < limit; j++) {
		BIT[j].init(n);
		memset(timer, 0, sizeof(timer));
		for (int i = 1; i <= n; i++)
			timer[depth[i] % j + 1]++;
		for (int i = 1; i <= j; i++)
			timer[i] += timer[i - 1];
		label(1, 0, j);
		for (int i = 1; i <= n; i
            
           

相關推薦

LOJ2322清華集訓 2017Hello world!

【題目連結】 點選開啟連結 【思路要點】 一個 1

LOJ2328清華集訓 2017避難所

【題目連結】 點選開啟連結 【思路要點】 令 x

LOJ2326清華集訓 2017簡單資料結構

【題目連結】 點選開啟連結 【思路要點】 注意到答案是 O

LOJ2323清華集訓 2017小 Y 和地鐵

【題目連結】 點選開啟連結 【思路要點】 很不錯的腦洞題。 附上官方題解。 時間複雜度 O

LOJ2324清華集訓 2017小 Y 和二叉樹

【題目連結】 點選開啟連結 【思路要點】 答案的第一位一定是編號最小的度數不為 3

LOJ2329清華集訓 2017我的生命已如風中殘燭

【題目連結】 點選開啟連結 【思路要點】 一個直觀的思路是模擬該過程,當路上遇到環的時候通過類似取模的手段加速。 注意到每繞一個環

LOJ2331清華集訓 2017某位歌姬的故事

【題目連結】 點選開啟連結 【思路要點】 注意到若一個位置被兩種音高 a

LOJ2330清華集訓 2017榕樹之心

【題目連結】 點選開啟連結 【思路要點】 首先,樹是二分圖,只有一側的點可能成為心。 維護每一棵子樹會產生的向下推動的次數可能的最大值

LOJ2327清華集訓 2017福若格斯

【題目連結】 點選開啟連結 【思路要點】 M

LOJ2320清華集訓 2017生成樹計數

【題目連結】【思路要點】連上\(a_i\)的限制,題目要求的實際上是\(\sum_{T}\prod_{i=1}^{N}a_i^{d_i}*d_i^{M}\sum_{i=1}^{N}d_i^{M}\)。我們知道樹的Prufer序列與樹點的度數密切相關,因此考慮使用Prufer序

LOJ2321清華集訓 2017無限之環

【題目連結】 【思路要點】 先說這道題的正解: 將棋盤看做一張二分圖,每一條邊拆成兩個點,分別屬於二分圖的一邊。 我們需要做一件類似於匹配的事情,同一條邊的兩側或是都沒有管道,或是都有管道。 通過合適的建邊我們能夠用最小費用最大流來解決本題。 時間複雜度

LOJ#2320. 清華集訓 2017生成樹計數

rac res 然而 除了 加法 wap OS 代碼 reg 題解 我,理解題解,用了一天 我,卡常數,又用了一天 到了最後,我才發現,我有個加法取模,寫的是while(c >= MOD) c -= MOD 我把while改成if,時間,少了 六倍。 六倍。 六倍!!

loj#2330. 清華集訓 2017榕樹之心樹形dp

傳送門 解題思路: 先考慮根是否可行,即步數是否能抵消完。 考慮w[x]w[x]表示xx的子樹內最少的消剩下的點數。 觀察發現,最難消的肯定是sizesize最大的兒子,設為 yy ,而且如果

LOJ#2330. 清華集訓 2017榕樹之心 -樹形dp

題解 先考慮根的情況(Subtask3Subtask3)。 根的每個兒子及其構成的子樹之間可以互相抵消。 設rem[i]rem[i]表示以ii為根的子樹最少的不能互相抵消的點數。 那

清華集訓 2017無限之環

無限之WA https://www.luogu.org/problemnew/show/P4003 本題如果知道是網路流的話,其實建圖不算特別神奇,但是比較麻煩。 資料範圍過大,插頭dp不能處理,而且是一個網格圖,考慮網路流。 先看是不是二分圖? 每個格子只會和相鄰四個格子發生關係 所以,黑白染色

LOJ2325清華集訓 2017小Y和恐怖的奴隸主(期望概率+矩陣快速冪)

LOJ2325「清華集訓 2017」小Y和恐怖的奴隸主 題意: "A fight? Count me in!" 要打架了,算我一個。 "Everyone, get in here!" 所有人,都過來! 小Y是一個喜歡玩遊戲的OIer。一天,她正在

LOJ2321清華集訓 2017無限之環

無限之環 題目描述 曾經有一款流行的遊戲,叫做InfinityLoopInfinityLoop,先來簡單的介紹一下這個遊戲: 遊戲在一個 n×mn×m的網格狀棋盤上進行,其中有些小方格中會有水管,水管可能在方格某些方向的邊界的中點有介面,所

清華集訓2017榕樹之心

name clear 方向 世界 oid 可行性 pre lin size 「清華集訓2017」榕樹之心 “已經快是嚴冬了,榕樹的葉子還沒落呢……” “榕樹是常綠樹,是看不到明顯的落葉季節的……” “唉……想不到已經七年了呢。榕樹還是當年的榕樹,你卻不是當年的你了……”

期望+矩陣乘法LOJ2325 [清華集訓 2017] 小 Y 和恐怖的奴隸主

【題目】 原題地址 BOSS \text{BOSS} BOSS初始有一個

UOJ #36清華集訓2014瑪裡苟斯

這怎麼想得到啊......... UOJ #36 題意:求隨機一個集合的子集的異或和的$k$次方的期望值,保證答案$ \lt 2^{63},1 \leq k \leq 5$ $ Solution:$ 首先考慮$ k=1$的時候怎麼做:如果某位上有$ 1$則有$ \frac{1}{2}$的