BZOJ 4867: [Ynoi2017]舌尖上的由乃

转化成dfs序上的问题,变成区间加和区间kth
可以用分块+二分,通常复杂度为 \(O(m\sqrt{n\log n}\log n)\),这道题里被卡掉了
设块大小为 \(B\),每一块内保持有序
修改时整块打上标记,零散块就现在有序表里分裂成两个序列,一个在修改的区间内,一个在修改的区间外,区间内加上值,再将两个序列归并,复杂度为 \(O(B)\)
查询时二分答案,整块里根据标记在有序表上二分,零散块再次将有序表分裂成值在区间内的一个有序表,然后再在这个新的有序表上二分,复杂度为 \(O(\dfrac{n}{B}\log^2 n)\)
\(B = \sqrt{n} \log n\) 时复杂度最优

#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) >> 1)
#define ll long long
#define db double
#define rep(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=b-1;i>=a;i--)
#define Edg int ccnt=1,head[N],to[N*2],ne[N*2];void addd(int u,int v){to[++ccnt]=v;ne[ccnt]=head[u];head[u]=ccnt;}void add(int u,int v){addd(u,v);addd(v,u);}
#define Edgc int ccnt=1,head[N],to[N*2],ne[N*2],c[N*2];void addd(int u,int v,int w){to[++ccnt]=v;ne[ccnt]=head[u];c[ccnt]=w;head[u]=ccnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
#define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
const int MOD = 1e9 + 7;
void M(int &x) {if (x >= MOD)x -= MOD; if (x < 0)x += MOD;}
int qp(int a, int b = MOD - 2) {int ans = 1; for (; b; a = 1LL * a * a % MOD, b >>= 1)if (b & 1)ans = 1LL * ans * a % MOD; return ans % MOD;}
int gcd(int a, int b) { while (b) { a %= b; std::swap(a, b); } return a; }

char buf[1 << 21], *p1 = buf, *p2 = buf;
inline char getc() {
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
inline int _() {
	int x = 0, f = 1; char ch = getc();
	while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getc(); }
	while (ch >= '0' && ch <= '9') { x = x * 10ll + ch - 48; ch = getc(); }
	return x * f;
}

const int N = 1e5 + 7;
int n, m, len, in[N], out[N], dfn, tol, limit, B, num, L[100], R[100], tag[100], belong[N];
std::pii a[N << 1];
Edgc

void dfs(int u, int f) {
	in[u] = ++dfn;
	a[dfn] = std::pii(f, dfn);
	es(u, i, v) dfs(v, f + c[i]);
	out[u] = dfn;
}
void build() {
	B = sqrt(n) * log(n) / log(2) + 5;
	num = n / B;
	if (n % B) num++;
	rep (i, 1, num + 1) {
		L[i] = (i - 1) * B + 1, R[i] = std::min(i * B, n);
		rep (j, L[i], R[i] + 1) belong[j] = i;
		std::sort(a + L[i], a + R[i] + 1);
	}
}
std::pii inq[N], outq[N];
void update(int p, int l, int r, int v) {
	int cnt1 = 0, cnt2 = 0;
	rep (i, L[p], R[p] + 1) {
		if (a[i].se >= l && a[i].se <= r) inq[++cnt1] = a[i];
		else outq[++cnt2] = a[i];
	}
	rep (i, 1, cnt1 + 1) inq[i].fi += v;
	int cur = L[p], i = 1, j = 1;
	while (i <= cnt1 && j <= cnt2) 
		a[cur++] = inq[i] < outq[j] ? inq[i++] : outq[j++];
	while (i <= cnt1) a[cur++] = inq[i++];
	while (j <= cnt2) a[cur++] = outq[j++];
}
void update(int l, int r, int v) {
	int p = belong[l], q = belong[r];
	if (p == q) {
		update(p, l, r, v);
		return;
	}
	rep (i, p + 1, q) tag[i] += v;
	update(p, l, R[p], v); update(q, L[q], r, v);
}
int query(int p, int v) {
	if (L[p] > R[p]) return 0;
	v -= tag[p];
	int l = L[p], r = R[p], ans = L[p] - 1;
	while (l <= r) {
		if (a[mid].fi <= v) ans = mid, l = mid + 1;
		else r = mid - 1;
	}
	return ans - L[p] + 1;
}
int kth(int x, int y, int k) {
	if (k > y - x + 1) return -1;
	int p = belong[x], q = belong[y];
	int st = n + 1, en = n;
	rep (i, L[p], R[p] + 1) if (a[i].se >= x && a[i].se <= y) a[++en] = a[i];
	L[num + 1] = st, R[num + 1] = en, tag[num + 1] = tag[p];
	st = en + 1;
	if (p < q) {
		rep (i, L[q], R[q] + 1) if (a[i].se <= y) a[++en] = a[i];
	}
	L[num + 2] = st, R[num + 2] = en, tag[num + 2] = tag[q];
	int l = 0, r = limit, ans = 0;
	while (l <= r) {
		int temp = query(num + 1, mid) + query(num + 2, mid);
		rep (i, p + 1, q) temp += query(i, mid);
		if (temp >= k) ans = mid, r = mid - 1;
		else l = mid + 1;
	}
	return ans;
}

int main() {
	n = _(), m = _(), len = _();
	rep (i, 2, n + 1) {
		int p = _(), cc = _(); limit += cc;
		addd(p, i, cc);
	}
	dfs(1, 0);
	build();
	for (int opt, u, k; m--; ) {
		opt = _(), u = _(), k = _();
		if (opt == 2) {
			update(in[u], out[u], k), limit += k;
		} else {
			printf("%d\n", kth(in[u], out[u], k));
		}
	}
	return 0;
}
posted @ 2020-02-24 10:20  Mrzdtz220  阅读(88)  评论(0编辑  收藏  举报