ZJOI 2019 補題記錄

去年花了大概並不長的時間口胡了四個 (D1T2, D1T3, D2T1, D2T2),感覺比 ZJOI 2018 不知道友好到哪裏去了。然後 D1T1 不會算複雜度跑路了,D2T3 只會 \O(nk^2\log(n)) (後面用奇技淫巧優化到了 \O(nk(k+\log(MAXA))\log(k)) 然後卡了。

在 little_waxberry 神仙的指點下意識到 D2T3 只用關心每條直線最上面的一次 occurence(也就是說剝掉上層凸殼之後上面的直線只會起到增加其它直線 rank 的作用而不會被計入答案),頓悟,才發現之前自己一直在試圖把凸殼前 k 層的完整形態求出來(其實前 k 層加起來就已經有 \O(nk^2) 段了,標算的複雜度是不可能做到的,這輩子都不可能做到的),然後會了。可能這就是菜吧。

感覺這個 2020 年狀態一直不太行……經常浮躁而無法靜下來去分析一個問題試圖突破……希望,能改改吧。

D1T1

由於某種原因鴿了。

人有多大膽,地有多大產。

考慮怎麼判斷和牌:dp 即可。dp[i][j][k][l] 表示考慮了值爲 [1, i] 的牌,有 j 個 (i-1, i, i+1) 的順子,k 個 (i, i+1, i+2) 的順子,l 個對子的方案數,再記一下不同對子個數的最大值。注意只存那些目前還沒和的狀態,總共只有幾百個。

再用一個 dp 套它,dp for dp. 時間複雜度 \O(n [\text{number of states}]).

D1T2

套路數據結構題

令 g(v) 表示節點 v 上有 tag 的概率並維護。遺憾的是這玩意沒法轉移。

觀察爲啥沒法轉移。考慮除了 g(v) 之外再維護 f(v) 表示 v 到根的鏈上至少有一個 tag 的概率。然後這二者可以相互轉移。

用線段樹維護。時間複雜度 \O(n \log(n))

#include <bits/stdc++.h>
#define rep(i, n) for(int i = 0; i < (int)(n); i ++)
#define rep1(i, n) for(int i = 1; i <= (int)(n); i ++)
#define MP make_pair

using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MOD = 998244353;
const int INV2 = (MOD + 1) / 2;
int pwi2[100005];

int n, m, sum;
int f[262144], g[262144];
int cnt[262144];

void pushdown(int v)
{
	cnt[v << 1] += cnt[v];
	f[v << 1] = (1 - pwi2[cnt[v]] + 1LL * f[v << 1] * pwi2[cnt[v]] + MOD) % MOD;
	cnt[v << 1 | 1] += cnt[v];
	f[v << 1 | 1] = (1 - pwi2[cnt[v]] + 1LL * f[v << 1 | 1] * pwi2[cnt[v]] + MOD) % MOD;
	cnt[v] = 0;
}
void modify(int rt, int cl, int cr, int l, int r, int ccnt)
{
	if(r < cl || l > cr) {
		sum = (sum - g[rt] + MOD) % MOD;
		g[rt] = 1LL * (g[rt] + f[rt]) * INV2 % MOD;
		sum = (sum + g[rt]) % MOD;
		return;
	}
	
	if(l <= cl && r >= cr) {
		cnt[rt] ++;
		sum = (sum - g[rt] + MOD) % MOD;
		g[rt] = 1LL * (g[rt] + 1) * INV2 % MOD;
		sum = (sum + g[rt]) % MOD;
		f[rt] = 1LL * (f[rt] + 1) * INV2 % MOD;
		return;
	}
	sum = (sum - g[rt] + MOD) % MOD;
	g[rt] = 1LL * g[rt] * INV2 % MOD;
	sum = (sum + g[rt]) % MOD;
	f[rt] = 1LL * f[rt] * INV2 % MOD;
	pushdown(rt);
	int mid = cl + cr >> 1;
	modify(rt << 1, cl, mid, l, r, ccnt);
	modify(rt << 1 | 1, mid + 1, cr, l, r, ccnt);
}

int main()
{
	scanf("%d%d", &n, &m);
	pwi2[0] = 1;
	rep1(i, m) pwi2[i] = 1LL * pwi2[i - 1] * INV2 % MOD; 
	int cur = 1;
	rep(i, m) {
		int t, l, r;
		scanf("%d", &t);
		if(t == 1) {
			scanf("%d%d", &l, &r);
			modify(1, 1, n, l, r, 0);
			cur = 2 * cur % MOD;
		} else {
			l = 1LL * cur * sum % MOD;
			printf("%d\n", l);
		}
	}
	return 0;
}

 

 

D1T3

2 * 2 矩乘的 1e5 n log^2 n,比想象中穩

設最終在根上的值爲 val

我們不關心一個節點上的具體值;我們只關心它和 val 的大小關係。

考慮我們對於每個 A \in [l - 1, r]  計算 ans \leq A 的葉子集合數量。

固定 A 之後,有些葉子只要得到控制權我們就能改變它和 val 的大小關係;有些則不行。記前者爲好的葉子,後者爲壞的葉子。

令 dp[v][1] 表示有多少種子樹 v 內的葉子集合滿足如果得到該集合的控制權,我們就可以改變 v 上的值與 val 的大小關係。轉移需討論 v 的節點類型和值。樸素 dp 是 \O(n (r - l + 1)) 的。

A 從 l - 1 掃到 r ,這個過程中葉子的好壞只會變化 n 次。使用動態 dp 維護即可。需要一棵樹剖。時間複雜度 \O(n \log^2(n))(可以優化至 \O(n \log(n)) )

#include <bits/stdc++.h>
#define rep(i, n) for(int i = 0; i < (int)(n); i ++)
#define rep1(i, n) for(int i = 1; i <= (int)(n); i ++)
#define MP make_pair

using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MOD = 998244353;

struct matrix
{
	int dat[2][2];
	matrix(int x = 0) {
		dat[0][1] = dat[1][0] = 0;
		dat[0][0] = dat[1][1] = x;
	}
	matrix(int a, int b, int c, int d)
	{
		dat[0][0] = a; dat[0][1] = b; dat[1][0] = c; dat[1][1] = d;
	}
	matrix(const matrix& oth)
	{
		memcpy(dat, oth.dat, 16);
	}
};
int mul(int a, int b)
{
	return 1LL * a * b % MOD;
}
matrix mul(const matrix& a, const matrix& b)
{
	matrix ret;
	rep(i, 2) rep(j, 2) rep(k, 2) ret.dat[i][j] = (ret.dat[i][j] + 1LL * a.dat[i][k] * b.dat[k][j]) % MOD;
	return ret;
}

template<class T>
struct segt
{
	vector<T> tre;
	int len;
	void init(int cl)
	{
		len = 1;
		while(len < (cl << 1)) len <<= 1;
		tre.resize(len);
		rep(i, len) tre[i] = 1;
	}
	
	void modify(int id, const T& dat)
	{
		id += len >> 1;
		tre[id] = dat;
		while(id > 1) {
			id >>= 1;
			tre[id] = mul(tre[id << 1], tre[id << 1 | 1]);
		}
	}
	
	T query()
	{
		return tre[1];
	}
};
segt<matrix> mt[200005];
segt<int> vt[200005], vt2[200005];

int n, l, r;
vector<int> G[200005], T[200005];
int val[200005], dep[200005], pre[200005];
int tp[200005];

void dfs0(int v, int par, int cd)
{
	dep[v] = cd;
	pre[v] = par;
	val[v] = cd & 1 ? 0 : n + 1;
	rep(i, G[v].size()) {
		int u = G[v][i];
		if(u == par) continue;
		dfs0(u, v, cd + 1);
		if(cd & 1) val[v] = max(val[v], val[u]);
		else val[v] = min(val[v], val[u]);
	}
	if(val[v] == 0 || val[v] == n + 1) val[v] = v;
}

void dfs1(int v, int par)
{
	if(val[v] == v) tp[v] = 2;
	else if((dep[v] & 1) && val[v] > val[1] || !(dep[v] & 1) && val[v] < val[1]) tp[v] = 0;
	else tp[v] = 1;
	rep(i, G[v].size()) {
		int u = G[v][i];
		if(u == par) continue;
		if(tp[v] || (dep[v] & 1) && val[u] > val[1] || !(dep[v] & 1) && val[u] < val[1]) dfs1(u, v); 
	}
}

int siz[200005], mu[200005];
int tnd[200005], tlf[200005], sid[200005];
void dfs2(int v)
{
	siz[v] = 1;
	mu[v] = -1;
	rep(i, T[v].size()) {
		int u = T[v][i];
		dfs2(u);
		siz[v] += siz[u];
		if(mu[v] == -1 || siz[u] > siz[mu[v]]) mu[v] = u;
	}
}

void dfs3(int v)
{
	if(tnd[v] == -1) tnd[v] = v;
	tlf[v] = v;
	rep(i, T[v].size()) {
		int u = T[v][i];
		sid[u] = i;
		if(u == mu[v]) tnd[u] = tnd[v];
		dfs3(u);
		if(u == mu[v]) tlf[v] = tlf[u];
	}
}

void dfs4(int v)
{
	if(tlf[v] == v) {
		mt[v].modify(0, matrix(2, 0, 0, 0));
		return;
	}
	rep(i, T[v].size()) {
		int u = T[v][i];
		dfs4(u);
		if(u == mu[v]) continue;
		matrix cur = mt[tlf[u]].query();
		int co = (cur.dat[0][0] + cur.dat[0][1]) % MOD, cs = tp[v] ? cur.dat[0][0] : cur.dat[0][1];
		vt[v].modify(i, co);
		vt2[v].modify(i, cs);
	}
	int co = vt[v].query(), cs = vt2[v].query();
	if(tp[v]) mt[tlf[v]].modify(dep[tlf[v]] - dep[v], matrix(cs, (co - cs + MOD) % MOD, 0, co));
	else mt[tlf[v]].modify(dep[tlf[v]] - dep[v], matrix(co, 0, (co - cs + MOD) % MOD, cs));
}

void build()
{
	dfs2(1);
	rep1(i, n) tnd[i] = -1;
	dfs3(1);
	rep1(i, n) if(tp[i] == 2) mt[i].init(dep[i] - dep[tnd[i]] + 1);
	else if(tp[i] != -1) {
		vt[i].init(T[i].size());
		vt2[i].init(T[i].size());
	}
	dfs4(1);
}

void modify(int v, const matrix& M)
{
	mt[v].modify(dep[tlf[v]] - dep[v], M);
	for(v = tnd[v]; pre[v] != -1; v = tnd[v]) {
		matrix cur = mt[tlf[v]].query();
		int co = (cur.dat[0][0] + cur.dat[0][1]) % MOD, cs = tp[pre[v]] ? cur.dat[0][0] : cur.dat[0][1];
		vt[pre[v]].modify(sid[v], co);
		vt2[pre[v]].modify(sid[v], cs);
		
		v = pre[v];
		co = vt[v].query(); cs = vt2[v].query();
		if(tp[v]) mt[tlf[v]].modify(dep[tlf[v]] - dep[v], matrix(cs, (co - cs + MOD) % MOD, 0, co));
		else mt[tlf[v]].modify(dep[tlf[v]] - dep[v], matrix(co, 0, (co - cs + MOD) % MOD, cs));
	}
}

int query()
{
	return mt[tlf[1]].query().dat[0][1];
}

vector<int> hv[200005];
int ans[200005];

int main()
{
	scanf("%d%d%d", &n, &l, &r);
	rep(i, n - 1) {
		int u, v;
		scanf("%d%d", &u, &v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dfs0(1, -1, 1);
	rep1(i, n) tp[i] = -1;
	dfs1(1, -1);
	
	int coef = 1;
	rep1(i, n) if(tp[i] != -1 && pre[i] != -1) T[pre[i]].push_back(i);
	else if(tp[i] == -1 && G[i].size() == 1) coef = 2 * coef % MOD;
	
	int cntl = 0;
	rep1(i, n) if(tp[i] == 2) {
		if(i < val[1]) hv[val[1] + 1 - i].push_back(i);
		else hv[i - val[1] + 1].push_back(i);
		cntl ++;
	}
	
	build();
	
	ans[0] = 0;
	rep1(i, n) {
		rep(j, hv[i].size()) modify(hv[i][j], matrix(1, 1, 0, 0));
		ans[i] = query();
	}
	
	ans[n] = 1;
	rep(i, cntl) ans[n] = ans[n] * 2 % MOD;
	rep(i, n + 1) ans[i] = 1LL * ans[i] * coef % MOD;
	ans[n] = (ans[n] - 1 + MOD) % MOD;
	for(int i = n; i >= 1; i --) ans[i] = (ans[i] - ans[i - 1] + MOD) % MOD;
	
	for(int i = l; i <= r; i ++) printf("%d ", ans[i]);
	return 0;
}

 

D2T1

當時口胡的時候還感覺這玩意挺妙的,寫的時候大概已經是爛大街的套路了。可能這就是鴿子的本質吧。

考慮 [x^t]F_{state} 表示 t 步後狀態爲 state 的概率,[x^t]G_{state} 表示 t 步後狀態首次爲 state 的概率。則 G_{state} = F_{state} / F_0。所求即爲 G'_{state}(1)

考慮怎麼求 F_{state}。令 f_{state} = \sum_{i=0}^{+\infty} \frac{{}[x^i] F_{state}}{i!}x^i 。則 f_{state} = \prod_{i=1}^n{\frac{\exp(prob_ix) + (-1)^{state_i}\exp(-prob_ix))}{2}}。可以將 f_{state} 寫成關於 \exp(x) 的多項式,然後利用 f = exp(kx) \iff F = \frac{1}{1-kx} 還原出 F_{state}。注意不用真正求出 F_{state} ,可以直接將 x = 1 代入(所以連 FFT 都不需要)。時間複雜度 \O(nM) 其中 M = \sum{prob_i}(可優化至 \O(M \log(M))

#include <bits/stdc++.h>
#define rep(i, n) for(int i = 0; i < (int)(n); i ++)
#define rep1(i, n) for(int i = 1; i <= (int)(n); i ++)
#define MP make_pair

using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MOD = 998244353;

int mem[200020];
int* dp = mem + 50005,* ndp = mem + 150015;

int n, s[105], p[105], tot;

int power(int x, int t)
{
	int ret = 1;
	while(t > 0) {
		if(t & 1) ret = 1LL * ret * x % MOD;
		x = 1LL * x * x % MOD;
		t >>= 1;
	}
	return ret;
}

int count()
{
	tot = 0;
	dp[0] = 1;
	rep(i, n) {
		for(int j = -tot - p[i]; j <= tot + p[i]; j ++) ndp[j] = 0;
		for(int j = -tot; j <= tot; j ++) {
			ndp[j + p[i]] = (ndp[j + p[i]] + dp[j]) % MOD;
			if(s[i]) ndp[j - p[i]] = (ndp[j - p[i]] - dp[j] + MOD) % MOD;
			else ndp[j - p[i]] = (ndp[j - p[i]] + dp[j]) % MOD;
		}
		tot += p[i];
		for(int j = -tot; j <= tot; j ++) dp[j] = ndp[j];
	}
	
	int ret = 0;
	int invt = power(tot, MOD - 2);
	for(int i = -tot; i < tot; i ++) ret = (ret + 1LL * dp[i] * power((1 + 1LL * (MOD - i) * invt) % MOD, MOD - 2)) % MOD;
	
	return ret; 
}

int main()
{
	scanf("%d", &n);
	rep(i, n) scanf("%d", &s[i]);
	rep(i, n) scanf("%d", &p[i]);
	int ans = count();
	rep(i, n) s[i] = 0;
	ans = (count() - ans + MOD) % MOD;
	printf("%d\n", ans);
	return 0;
}

D2T2

套路數據結構題

固定節點 v 求出和 v 之間能進行貿易的節點個數。這即是過 v 的路徑端點構成的虛樹經過的節點個數。

考慮假如我們有所有過 v 的所有路徑端點集合 S 並按照 dfs 序排序,那麼虛樹經過的節點數就是 \sum{dep[S_i]} - \sum{dep[LCA(S_i, S_{i+1})] - dep[LCA(S_1, S_{|S|})]。用線段樹維護 S ,自底向上處理 v 並使用線段樹合併維護即可。時間複雜度 \O(n \log(n)) 。

#include <bits/stdc++.h>
#define rep(i, n) for(int i = 0; i < (int)(n); i ++)
#define rep1(i, n) for(int i = 1; i <= (int)(n); i ++)
#define MP make_pair

using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MOD = 998244353;

int n, m, s[100005], t[100005];
vector<int> G[100005];
int dep[100005]; 
int dfn[100005];
int seq[200005], cnt;
int st[200005][25];

void dfs0(int v, int par, int cd)
{
	dep[v] = cd;
	dfn[v] = cnt;
	seq[cnt ++] = v;
	rep(i, G[v].size()) {
		int u = G[v][i];
		if(u == par) continue;
		dfs0(u, v, cd + 1);
		seq[cnt ++] = v;
	}
}

void init()
{
	dfs0(1, -1, 0);
	rep(i, cnt) st[i][0] = seq[i];
	rep1(i, 17) rep(j, cnt)
	st[j][i] = j + (1 << i - 1) >= cnt || dep[st[j][i - 1]] < dep[st[j + (1 << i - 1)][i - 1]] ?
	st[j][i - 1] : st[j + (1 << i - 1)][i - 1];
}

int lca(int u, int v)
{
	u = dfn[u];
	v = dfn[v];
	if(u > v) swap(u, v);
	int l = 31 - __builtin_clz(v - u + 1);
	return dep[st[u][l]] < dep[st[v - (1 << l) + 1][l]] ? st[u][l] : st[v - (1 << l) + 1][l];
}

struct tnode
{
	int lv, rv, sum, cnt;
	tnode* lson,* rson;
	tnode(int x = -1)
	{
		lv = rv = x;
		cnt = x == -1 ? 0 : 1;
		sum = dep[seq[x]];
		lson = rson = NULL;
	}
};

void pushup(tnode*& cur)
{
	if(cur->lson == NULL && cur->rson == NULL) cur = NULL;
	else if(cur->lson == NULL) {
		cur->lv = cur->rson->lv;
		cur->rv = cur->rson->rv;
		cur->sum = cur->rson->sum; 
	} else if(cur->rson == NULL) {
		cur->lv = cur->lson->lv;
		cur->rv = cur->lson->rv;
		cur->sum = cur->lson->sum;
	} else {
		cur->lv = cur->lson->lv;
		cur->rv = cur->rson->rv;
		cur->sum = cur->lson->sum + cur->rson->sum - dep[lca(seq[cur->lson->rv], seq[cur->rson->lv])];
	}
}

void add_t(tnode*& cur, int x, int cl = 0, int cr = 262143)
{
	if(cl == cr) {
		if(cur == NULL) cur = new tnode(x);
		else cur->cnt ++; 
		return;
	}
	if(cur == NULL) cur = new tnode();
	int mid = cl + cr >> 1;
	if(x <= mid) add_t(cur->lson, x, cl, mid);
	else add_t(cur->rson, x, mid + 1, cr);
	pushup(cur);
}

void rem_t(tnode*& cur, int x, int cl = 0, int cr = 262143)
{
	if(cl == cr) {
		cur->cnt --;
		if(cur->cnt == 0) cur = NULL;
		return;
	}
	int mid = cl + cr >> 1;
	if(x <= mid) rem_t(cur->lson, x, cl, mid);
	else rem_t(cur->rson, x, mid + 1, cr);
	pushup(cur);
}

void merge_t(tnode*& ret, tnode* u, tnode* v, int cl = 0, int cr = 262143)
{
	if(u == NULL) ret = v;
	else if(v == NULL) ret = u;
	else {
		ret = u;
		if(cl == cr) {
			ret->cnt += v->cnt;
			return;
		}
		int mid = cl + cr >> 1;
		merge_t(ret->lson, u->lson, v->lson, cl, mid);
		merge_t(ret->rson, u->rson, v->rson, mid + 1, cr);
		pushup(ret);
	}
}

int query_t(tnode* cur)
{
	return cur == NULL ? 0 : cur->sum - dep[lca(seq[cur->lv], seq[cur->rv])];
}

vector<int> inq[100005], outq[100005];
tnode* tre[100005];
LL ans;
void dfs1(int v, int par)
{
	rep(i, inq[v].size()) {
		add_t(tre[v], dfn[s[inq[v][i]]]);
		add_t(tre[v], dfn[t[inq[v][i]]]);
	}
	rep(i, G[v].size()) {
		int u = G[v][i];
		if(u == par) continue;
		dfs1(u, v);
		merge_t(tre[v], tre[v], tre[u]);
	}
	ans += query_t(tre[v]);
	rep(i, outq[v].size()) rep(j, 2) {
		rem_t(tre[v], dfn[s[outq[v][i]]]);
		rem_t(tre[v], dfn[t[outq[v][i]]]);
	}
}

int main()
{
	scanf("%d%d", &n, &m);
	rep(i, n - 1) {
		int u, v;
		scanf("%d%d", &u, &v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	rep(i, m) scanf("%d%d", &s[i], &t[i]);
	
	init();
	
	rep(i, m) {
		inq[s[i]].push_back(i);
		inq[t[i]].push_back(i);
		outq[lca(s[i], t[i])].push_back(i);
	}
	
	dfs1(1, -1);
	ans /= 2;
	printf("%lld\n", ans);
	return 0;
}

 

D2T3

感覺這題並沒有太難但我就是不會做

注意到我們只需要求每條直線的最小排名。考慮假如已經求得了排名爲 1...i 的直線,要求排名爲 i + 1 的直線。

考慮計算出所有排名不爲 1...i 的直線構成的凸殼。一條直線排名爲 i + 1 當且僅當存在一個非負整數 x_0 滿足位置 x = x_0 處該直線在凸殼上且僅有 i 條排名爲 1...i 的直線與 x = x_0 的交點嚴格在凸殼的上方。

對每條排名爲 1...i 的直線 L ,二分出 L 和凸殼的交點然後進行區間加即可。注意三線共點。

時間複雜度 \O(nk \log(n))

#include <bits/stdc++.h>
#define rep(i, n) for(int i = 0; i < (int)(n); i ++)
#define rep1(i, n) for(int i = 1; i <= (int)(n); i ++)
#define MP make_pair

using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL INF = 0x3f3f3f3f3f3f3f3f;

int n, k;
LL x[100005], y[100005];
int ans[100005];
int perm[100005];
int conv[100005], cnt;
vector<pair<LL, int> > qy[100005];
LL tl[100005], tr[100005];
LL apos[200005];
int tot, atot;
int scnt[200005];

bool cmp(int i, int j)
{
	return x[i] < x[j] || x[i] == x[j] && y[i] > y[j];
}

bool can_rep(int i, int j, int k)
{
	return __int128(y[k] - y[i]) * (x[j] - x[i]) >= __int128(y[j] - y[i]) * (x[k] - x[i]);
}

void solve_k(int dep)
{
	cnt = 0;
	rep(i, n) {
		int cur = perm[i];
		if(ans[cur] != -1) continue;
		if(cnt == 0) conv[cnt ++] = cur;
		else if(x[conv[cnt - 1]] == x[cur]) continue;
		else {
			while(cnt >= 2 && can_rep(conv[cnt - 2], conv[cnt - 1], cur)) cnt --;
			conv[cnt ++] = cur;
		}
	}
	if(cnt == 0) return;
	
	tot = 0;
	rep(i, n) {
		int cur = perm[i];
		if(ans[cur] == -1) continue;
		int pos = lower_bound(conv, conv + cnt, cur, cmp) - conv;
		LL lp = -INF, rp = INF;
		
		int cl = 0, cr = pos - 1;
		while(cl < cr) {
			int mid = cl + cr >> 1;
			if(can_rep(conv[mid], conv[mid + 1], cur)) cr = mid;
			else cl = mid + 1;
		}
		if(cl == cr && __int128(lp) * (x[conv[cl]] - x[cur]) + y[conv[cl]] - y[cur] > 0) {
			lp = 1 - (y[conv[cl]] - y[cur]) / (x[conv[cl]] - x[cur]);
			while(lp * (x[conv[cl]] - x[cur]) + y[conv[cl]] - y[cur] < 0) lp --;
			lp ++;
		}
		
		cl = pos; cr = cnt - 1;
		while(cl < cr) {
			int mid = cl + cr >> 1;
			if(can_rep(cur, conv[mid], conv[mid + 1])) cl = mid + 1;
			else cr = mid;
		}
		if(cl == cr && __int128(rp) * (x[conv[cr]] - x[cur]) + y[conv[cr]] - y[cur] > 0) {
			rp = -1 - (y[conv[cr]] - y[cur]) / (x[conv[cr]] - x[cur]);
			while(rp * (x[conv[cr]] - x[cur]) + y[conv[cr]] - y[cur] < 0) rp ++;
			rp --;
		}
		
		if(lp > rp) continue;
		tl[tot] = lp;
		tr[tot] = rp + 1;
		tot ++;
	}
	rep(i, tot) {
		apos[i * 2] = tl[i];
		apos[i * 2 + 1] = tr[i];
	}
	apos[tot * 2] = -INF;
	sort(apos, apos + tot * 2 + 1);
	atot = unique(apos, apos + tot * 2 + 1) - apos;
	rep(i, tot) {
		tl[i] = lower_bound(apos, apos + atot, tl[i]) - apos;
		tr[i] = lower_bound(apos, apos + atot, tr[i]) - apos;
	}
	rep(i, atot + 1) scnt[i] = 0;
	rep(i, tot) {
		scnt[tl[i]] ++;
		scnt[tr[i]] --;
	}
	rep1(i, atot) scnt[i] += scnt[i - 1];
	
	rep(i, cnt) {
		int cur = conv[i];
		LL lp = -INF, rp = INF;
		if(i > 0) {
			lp = 1 - (y[cur] - y[conv[i - 1]]) / (x[cur] - x[conv[i - 1]]);
			while(lp * (x[cur] - x[conv[i - 1]]) + y[cur] - y[conv[i - 1]] >= 0) lp --;
			lp ++;
		}
		if(i < cnt - 1) {
			rp = -1 - (y[cur] - y[conv[i + 1]]) / (x[cur] - x[conv[i + 1]]);
			while(rp * (x[cur] - x[conv[i + 1]]) + y[cur] - y[conv[i + 1]] >= 0) rp ++;
			rp --;
		}
		
		lp = max(lp, 0LL);
		if(lp > rp) continue;
		
		int cl = upper_bound(apos, apos + atot, lp) - apos - 1;
		int cr = upper_bound(apos, apos + atot, rp) - apos - 1;
		for(int i = cl; i <= cr; i ++) if(scnt[i] == dep) {
			ans[cur] = dep + 1;
			break;
		}
	}
	
	rep(i, n) {
		int cur = perm[i];
		if(ans[cur] != -1) continue;
		int pos = lower_bound(conv, conv + cnt, cur, cmp) - conv;
		if(pos == 0 || pos == cnt) continue;
		LL cp = -(y[conv[pos]] - y[conv[pos - 1]]) / (x[conv[pos]] - x[conv[pos - 1]]);
		cp = max(cp, 0LL);
		if(cp * (x[conv[pos]] - x[conv[pos - 1]]) + y[conv[pos]] - y[conv[pos - 1]] != 0) continue;
		if(cp * (x[conv[pos]] - x[cur]) + y[conv[pos]] - y[cur] != 0) continue;
		
		int cc = upper_bound(apos, apos + atot, cp) - apos - 1;
		if(scnt[cc] == dep) ans[cur] = dep + 1;
  	}
}

int main()
{
	scanf("%d%d", &n, &k);
	rep(i, n) scanf("%lld%lld", &x[i], &y[i]);
	rep(i, n) ans[i] = -1;
	
	rep(i, n) perm[i] = i;
	sort(perm, perm + n, cmp);
	
	rep(i, k) solve_k(i);
	
	rep(i, n) printf("%d\n", ans[i]);
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章