去年花了大概並不長的時間口胡了四個 (D1T2, D1T3, D2T1, D2T2),感覺比 ZJOI 2018 不知道友好到哪裏去了。然後 D1T1 不會算複雜度跑路了,D2T3 只會 (後面用奇技淫巧優化到了 然後卡了。
在 little_waxberry 神仙的指點下意識到 D2T3 只用關心每條直線最上面的一次 occurence(也就是說剝掉上層凸殼之後上面的直線只會起到增加其它直線 rank 的作用而不會被計入答案),頓悟,才發現之前自己一直在試圖把凸殼前 層的完整形態求出來(其實前 層加起來就已經有 段了,標算的複雜度是不可能做到的,這輩子都不可能做到的),然後會了。可能這就是菜吧。
感覺這個 2020 年狀態一直不太行……經常浮躁而無法靜下來去分析一個問題試圖突破……希望,能改改吧。
D1T1
由於某種原因鴿了。
人有多大膽,地有多大產。
考慮怎麼判斷和牌:dp 即可。 表示考慮了值爲 的牌,有 個 的順子, 個 的順子, 個對子的方案數,再記一下不同對子個數的最大值。注意只存那些目前還沒和的狀態,總共只有幾百個。
再用一個 dp 套它,dp for dp. 時間複雜度 .
D1T2
套路數據結構題
令 表示節點 上有 tag 的概率並維護。遺憾的是這玩意沒法轉移。
觀察爲啥沒法轉移。考慮除了 之外再維護 表示 到根的鏈上至少有一個 tag 的概率。然後這二者可以相互轉移。
用線段樹維護。時間複雜度 。
#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,比想象中穩
設最終在根上的值爲 。
我們不關心一個節點上的具體值;我們只關心它和 的大小關係。
考慮我們對於每個 計算 的葉子集合數量。
固定 之後,有些葉子只要得到控制權我們就能改變它和 的大小關係;有些則不行。記前者爲好的葉子,後者爲壞的葉子。
令 表示有多少種子樹 內的葉子集合滿足如果得到該集合的控制權,我們就可以改變 上的值與 的大小關係。轉移需討論 的節點類型和值。樸素 dp 是 的。
從 掃到 ,這個過程中葉子的好壞只會變化 次。使用動態 dp 維護即可。需要一棵樹剖。時間複雜度 (可以優化至 )
#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
當時口胡的時候還感覺這玩意挺妙的,寫的時候大概已經是爛大街的套路了。可能這就是鴿子的本質吧。
考慮 表示 步後狀態爲 的概率, 表示 步後狀態首次爲 的概率。則 。所求即爲 。
考慮怎麼求 。令 。則 。可以將 寫成關於 的多項式,然後利用 還原出 。注意不用真正求出 ,可以直接將 代入(所以連 FFT 都不需要)。時間複雜度 其中 。(可優化至 )。
#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
套路數據結構題
固定節點 求出和 之間能進行貿易的節點個數。這即是過 的路徑端點構成的虛樹經過的節點個數。
考慮假如我們有所有過 的所有路徑端點集合 並按照 dfs 序排序,那麼虛樹經過的節點數就是 。用線段樹維護 ,自底向上處理 並使用線段樹合併維護即可。時間複雜度 。
#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
感覺這題並沒有太難但我就是不會做
注意到我們只需要求每條直線的最小排名。考慮假如已經求得了排名爲 的直線,要求排名爲 的直線。
考慮計算出所有排名不爲 的直線構成的凸殼。一條直線排名爲 當且僅當存在一個非負整數 滿足位置 處該直線在凸殼上且僅有 條排名爲 的直線與 的交點嚴格在凸殼的上方。
對每條排名爲 的直線 ,二分出 和凸殼的交點然後進行區間加即可。注意三線共點。
時間複雜度 。
#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;
}