整体二分做题笔记

就是把所有询问一起二分一个 \(mid\),根据这些询问的答案和 \(mid\) 的关系分成两种询问,再分别递归处理。

重点:值域上的分治

如要查询区间排名为 \(k\) 的数,且区间有 \(p\) 个数小于等于 \(mid\),则根据 \(p\)\(k\) 的关系将查询分为两类。

把修改看作删除和插入,则我们只对小于等于 \(mid\) 的数进行 \(update\),同样分成两类,这样可以通过 Dynamic Rankings

对于 二逼平衡树\(2\)\(3\) 操作已经在上面提到。对于 \(1\) 操作,考虑当前 \(k>mid\) 时,用全部的 \(k<=mid\) 更新答案。对于 \(4\) 操作,需要用线段树维护区间最大值,考虑当 \(k>mid\) 时,用 \(k<=mid\) 的最大值去更新答案。对于这题,\(3\) 操作的撤回有 \(max\)\(sum\)。考虑这题只有单点修改,即叶子节点的 \(sum\leq 1\),所以对于删除操作,我们直接 \(Renew\) 这个叶子节点并把信息往上传即可,具体实现可参考代码。对于 \(5\) 操作,可以看作是对所有数取反后求前趋。

\(\text{Code}(二逼平衡树)\)

#include <bits/stdc++.h>
//#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std;
const int N = 200010;
inline int read()
{
    int s = 0, w = 1;
    ri char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
        s = (s << 3) + (s << 1) + (ch ^ 48), ch = getchar();
    return s * w;
}
int n, m, a[N], ta[N], pp, tb[N];
struct Query
{
    int x, y, k, opt, id;
} q[N], tmp[N], q1[N], q2[N];
int cnt, Ans[N], sum[N << 2], mx[N << 2];
#define lc (x << 1)
#define rc (x << 1 | 1)
inline void Push_Up(int x)
{
    sum[x] = sum[lc] + sum[rc];
    mx[x] = max(mx[lc], mx[rc]);
}
void UpDate(int pos, int l, int r, int x, int k1, int k2)
{
    if (l == r)
    {
        mx[x] = k1;
        sum[x] += k2;
        return;
    }
    int mid = (l + r) / 2;
    if (pos <= mid)
        UpDate(pos, l, mid, lc, k1, k2);
    else
        UpDate(pos, mid + 1, r, rc, k1, k2);
    Push_Up(x);
}
int AskS(int u, int v, int l, int r, int x)
{
    if (l >= u && r <= v)
        return sum[x];
    int mid = (l + r) / 2, tt = 0;
    if (u <= mid)
        tt += AskS(u, v, l, mid, lc);
    if (v > mid)
        tt += AskS(u, v, mid + 1, r, rc);
    return tt;
}
int AskMx(int u, int v, int l, int r, int x)
{
    if (l >= u && r <= v)
        return mx[x];
    int mid = (l + r) / 2, tt = -2147483647;
    if (u <= mid)
        tt = max(tt, AskMx(u, v, l, mid, lc));
    if (v > mid)
        tt = max(tt, AskMx(u, v, mid + 1, r, rc));
    return tt;
}
void Renew(int pos, int l, int r, int x)
{
    if (l == r)
    {
        sum[x] = 0;
        mx[x] = -2147483647;
        return;
    }
    int mid = (l + r) / 2;
    if (pos <= mid)
        Renew(pos, l, mid, lc);
    else
        Renew(pos, mid + 1, r, rc);
    Push_Up(x);
}
#undef lc
#undef rc
void Solvep(int u, int v, int l, int r)
{
    if (u > v || l > r)
        return;
    if (l == r)
    {
        for (ri int i = u; i <= v; i++)
            if (q[i].opt == 2)
                Ans[q[i].id] = tb[l];
        return;
    }
    int mid = (l + r) / 2;
    int tot1, tot2;
    tot1 = tot2 = 0;
    for (ri int i = u; i <= v; i++)
    {
        if (q[i].opt == 1)
        {
            if (q[i].k <= mid)
                q1[++tot1] = q[i];
            else
            {
                Ans[q[i].id] += AskS(q[i].x, q[i].y, 1, n, 1);
                q2[++tot2] = q[i];
            }
        }
        else if (q[i].opt == 2)
        {
            int gt = AskS(q[i].x, q[i].y, 1, n, 1);
            if (q[i].k <= gt)
                q1[++tot1] = q[i];
            else
            {
                q[i].k -= gt;
                q2[++tot2] = q[i];
            }
        }
        else if (q[i].opt == 3)
        {
            if (q[i].y <= mid)
            {
                q1[++tot1] = q[i];
                if (q[i].k == 1)
                    UpDate(q[i].x, 1, n, 1, q[i].y, q[i].k);
                else
                    Renew(q[i].x, 1, n, 1);
            }
            else
                q2[++tot2] = q[i];
        }
        else if (q[i].opt == 4)
        {
            if (q[i].k <= mid)
                q1[++tot1] = q[i];
            else
            {
                int num = AskMx(q[i].x, q[i].y, 1, n, 1);
                if (num >= 0)
                    Ans[q[i].id] = max(Ans[q[i].id], tb[num]);
                q2[++tot2] = q[i];
            }
        }
        else
            q1[++tot1] = q[i];
    }
    for (ri int i = 1; i <= tot1; i++)
    {
        q[u + i - 1] = q1[i];
        if (q1[i].opt == 3)
            Renew(q1[i].x, 1, n, 1);
    }
    for (ri int i = 1; i <= tot2; i++)
        q[u + tot1 + i - 1] = q2[i];
    Solvep(u, u + tot1 - 1, l, mid);
    Solvep(u + tot1, v, mid + 1, r);
}
void Solven(int u, int v, int l, int r)
{
    if (u > v || l >= r)
        return;
    int mid = (l + r) / 2;
    int tot1, tot2;
    tot1 = tot2 = 0;
    for (ri int i = u; i <= v; i++)
    {
        if (q[i].opt == 3)
        {
            if (q[i].y <= mid)
            {
                q1[++tot1] = q[i];
                if (q[i].k == 1)
                    UpDate(q[i].x, 1, n, 1, q[i].y, q[i].k);
                else
                    Renew(q[i].x, 1, n, 1);
            }
            else
                q2[++tot2] = q[i];
        }
        else if (q[i].opt == 5)
        {
            if (q[i].k <= mid)
                q1[++tot1] = q[i];
            else
            {
                q2[++tot2] = q[i];
                int num = AskMx(q[i].x, q[i].y, 1, n, 1);
                if (num >= 0)
                    Ans[q[i].id] = min(Ans[q[i].id], tb[pp + 1 - num]);
            }
        }
        else
            q1[++tot1] = q[i];
    }
    for (ri int i = 1; i <= tot1; i++)
    {
        q[u + i - 1] = q1[i];
        if (q1[i].opt == 3)
            Renew(q1[i].x, 1, n, 1);
    }
    for (ri int i = 1; i <= tot2; i++)
        q[u + tot1 + i - 1] = q2[i];
    Solven(u, u + tot1 - 1, l, mid);
    Solven(u + tot1, v, mid + 1, r);
}
signed main()
{
    n = read(), m = read();
    for (ri int i = 0; i < (N << 2); i++)
        mx[i] = -2147483647;
    for (ri int i = 1; i <= n; i++)
    {
        a[i] = ta[++pp] = read();
        cnt++, q[cnt] = (Query){i, a[i], 1, 3, cnt}, Ans[cnt] = -1;
    }
    for (ri int i = 1; i <= m; i++)
    {
        int opt, x, y;
        opt = read(), x = read(), y = read();
        if (opt != 3)
        {
            int k = read();
            if (opt != 2)
                ta[++pp] = k;
            cnt++, q[cnt] = (Query){x, y, k, opt, cnt};
            if (opt == 4)
                Ans[cnt] = -2147483647;
            if (opt == 5)
                Ans[cnt] = 2147483647;
            if (opt == 1)
                Ans[cnt] = 1;
        }
        else
        {
            cnt++, q[cnt] = (Query){x, a[x], -1, 3, cnt}, Ans[cnt] = -1;
            cnt++, q[cnt] = (Query){x, y, 1, 3, cnt}, Ans[cnt] = -1;
            a[x] = y, ta[++pp] = y;
        }
    }
    sort(ta + 1, ta + 1 + pp);
    pp = unique(ta + 1, ta + 1 + pp) - ta - 1;
    for (ri int i = 1; i <= cnt; i++)
    {
        if (q[i].opt == 3)
        {
            int x = q[i].y;
            q[i].y = lower_bound(ta + 1, ta + 1 + pp, q[i].y) - ta;
            tb[q[i].y] = x;
        }
        else if (q[i].opt != 2)
        {
            int x = q[i].k;
            q[i].k = lower_bound(ta + 1, ta + 1 + pp, q[i].k) - ta;
            tb[q[i].k] = x;
        }
    }
    for (ri int i = 1; i <= cnt; i++)
        tmp[i] = q[i];
    Solvep(1, cnt, 1, pp);
    for (ri int i = 1; i <= cnt; i++)
    {
        q[i] = tmp[i];
        if (q[i].opt == 3)
            q[i].y = pp + 1 - q[i].y;
        else if (q[i].opt != 2)
            q[i].k = pp + 1 - q[i].k;
    }
    Solven(1, cnt, 1, pp);
    for (ri int i = 1; i <= cnt; i++)
        if (~Ans[i])
            printf("%lld\n", Ans[i]);
    return 0;
}

[ZJOI2013]K大数查询

\(\text{Solution}:\)

\(c\) 加入 \([L,R]\) 区间内的集合中等价于在整体二分时区间修改,查询就是单点查询,故可以用树状数组维护。

\(\text{Code}:\)

#include <bits/stdc++.h>
//#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std;
const int N = 100010;
inline int read()
{
    int s = 0, w = 1;
    ri char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
        s = (s << 3) + (s << 1) + (ch ^ 48), ch = getchar();
    return s * w;
}
int n, m, ta[N], pp, tb[N];
struct Query
{
    int x, y, k, opt, id;
} q[N], q1[N], q2[N];
int cnt, Ans[N];
struct BIT
{
    int c1[N], c2[N];
    inline int lowbit(int x) { return x & (-x); }
    inline void Add(int x, int p)
    {
        int gg = x;
        for (; x <= n; x += lowbit(x))
            c1[x] += p, c2[x] += gg * p;
    }
    inline int Ask(int x)
    {
        int tt = 0, gg = x + 1;
        for (; x; x -= lowbit(x))
            tt += gg * c1[x] - c2[x];
        return tt;
    }
} A;
void Solve(int u, int v, int l, int r)
{
    if (u > v || l > r)
        return;
    if (l == r)
    {
        for (ri int i = u; i <= v; i++)
            if (q[i].opt == 2)
                Ans[q[i].id] = l;
        return;
    }
    int mid = (l + r) / 2;
    int tot1, tot2;
    tot1 = tot2 = 0;
    for (ri int i = u; i <= v; i++)
    {
        if (q[i].opt == 1)
        {
            if (q[i].k <= mid)
                q1[++tot1] = q[i];
            else
            {
                q2[++tot2] = q[i];
                A.Add(q[i].x, 1), A.Add(q[i].y + 1, -1);
            }
        }
        else
        {
            int gt = A.Ask(q[i].y) - A.Ask(q[i].x - 1);
            if (q[i].k <= gt)
                q2[++tot2] = q[i];
            else
            {
                q[i].k -= gt;
                q1[++tot1] = q[i];
            }
        }
    }
    for (ri int i = 1; i <= tot1; i++)
        q[u + i - 1] = q1[i];
    for (ri int i = 1; i <= tot2; i++)
    {
        q[u + tot1 + i - 1] = q2[i];
        if (q2[i].opt == 1)
            A.Add(q2[i].x, -1), A.Add(q2[i].y + 1, 1);
    }
    Solve(u, u + tot1 - 1, l, mid);
    Solve(u + tot1, v, mid + 1, r);
}
signed main()
{
    n = read(), m = read();
    for (ri int i = 1; i <= m; i++)
    {
        int opt, l, r, c;
        opt = read(), l = read(), r = read(), c = read();
        cnt++, q[cnt] = (Query){l, r, c, opt, i};
        if (opt == 1)
            ta[++pp] = c;
    }
    sort(ta + 1, ta + 1 + pp);
    pp = unique(ta + 1, ta + 1 + pp) - ta - 1;
    for (ri int i = 1; i <= m; i++)
    {
        if (q[i].opt == 1)
        {
            int x = q[i].k;
            q[i].k = lower_bound(ta + 1, ta + 1 + pp, x) - ta;
            tb[q[i].k] = x;
        }
    }
    Solve(1, cnt, 1, pp);
    for (ri int i = 1; i <= cnt; i++)
        if (Ans[i])
            printf("%lld\n", tb[Ans[i]]);
    return 0;
}

[国家集训队]矩阵乘法

\(\text{Solution}:\)

将一维树状数组改为二维树状数组即可。

\(\text{Code}:\)

#include <bits/stdc++.h>
//#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std;
const int N = 510, M = 500010;
inline int read()
{
    int s = 0, w = 1;
    ri char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
        s = (s << 3) + (s << 1) + (ch ^ 48), ch = getchar();
    return s * w;
}
int n, m;
int a[N][N], ta[M], pp, tb[M];
struct BIT
{
    int c[N][N];
    inline int lowbit(int x) { return x & (-x); }
    inline void Add(int x, int y, int p)
    {
        for (ri int i = x; i <= n; i += lowbit(i))
            for (ri int j = y; j <= n; j += lowbit(j))
                c[i][j] += p;
    }
    inline int Ask(int x, int y)
    {
        int tt = 0;
        for (ri int i = x; i; i -= lowbit(i))
            for (ri int j = y; j; j -= lowbit(j))
                tt += c[i][j];
        return tt;
    }
} A;
struct Query
{
    int x, y, dx, dy, k, opt, id;
} q[M], q1[M], q2[M];
int cnt, Ans[M];
void Solve(int u, int v, int l, int r)
{
    if (u > v || l > r)
        return;
    if (l == r)
    {
        for (ri int i = u; i <= v; i++)
            if (q[i].opt == 2)
                Ans[q[i].id] = l;
        return;
    }
    int mid = (l + r) / 2;
    int tot1, tot2;
    tot1 = tot2 = 0;
    for (ri int i = u; i <= v; i++)
    {
        if (q[i].opt == 1)
        {
            if (q[i].k <= mid)
            {
                q1[++tot1] = q[i];
                A.Add(q[i].x, q[i].y, 1);
            }
            else
                q2[++tot2] = q[i];
        }
        else
        {
            int gt = A.Ask(q[i].dx, q[i].dy) - A.Ask(q[i].dx, q[i].y - 1) - A.Ask(q[i].x - 1, q[i].dy) + A.Ask(q[i].x - 1, q[i].y - 1);
            if (q[i].k <= gt)
                q1[++tot1] = q[i];
            else
            {
                q[i].k -= gt;
                q2[++tot2] = q[i];
            }
        }
    }
    for (ri int i = 1; i <= tot1; i++)
    {
        q[u + i - 1] = q1[i];
        if (q1[i].opt == 1)
            A.Add(q1[i].x, q1[i].y, -1);
    }
    for (ri int i = 1; i <= tot2; i++)
        q[u + tot1 + i - 1] = q2[i];
    Solve(u, u + tot1 - 1, l, mid);
    Solve(u + tot1, v, mid + 1, r);
}
signed main()
{
    n = read(), m = read();
    for (ri int i = 1; i <= n; i++)
        for (ri int j = 1; j <= n; j++)
            a[i][j] = read(), ta[++pp] = a[i][j];
    sort(ta + 1, ta + 1 + pp);
    pp = unique(ta + 1, ta + 1 + pp) - ta - 1;
    for (ri int i = 1; i <= n; i++)
        for (ri int j = 1; j <= n; j++)
        {
            int x = a[i][j];
            a[i][j] = lower_bound(ta + 1, ta + 1 + pp, x) - ta;
            tb[a[i][j]] = x;
            cnt++, q[cnt] = (Query){i, j, i, j, a[i][j], 1, cnt};
        }
    for (ri int i = 1; i <= m; i++)
    {
        int lx, ly, rx, ry, k;
        lx = read(), ly = read(), rx = read(), ry = read(), k = read();
        cnt++, q[cnt] = (Query){lx, ly, rx, ry, k, 2, cnt};
    }
    Solve(1, cnt, 1, pp);
    for (ri int i = 1; i <= cnt; i++)
        if (Ans[i])
            printf("%d\n", tb[Ans[i]]);
    return 0;
}

[POI2011]MET-Meteors

\(\text{Solution}:\)

破环为链,树状数组维护 \(2m\) 个节点。查询时将这个点对应在 \(2m\) 上的所有点都计算一遍。注意到此题值域较大,故当 \(gt\geq q[i].k\) 时,可以直接结束这个点的查询。为了方便,我们可以让答案值域为 \([1,K+1]\),这样如果 \(Ans_{i}=K+1\),那么这个查询应该输出 NIE

\(\text{Code}:\)

#include <bits/stdc++.h>
//#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std; const int N=600010;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,m,K,p[N/2];
vector<int> a[N/2];
struct Query
{
	int x,y,k,opt,id;
}q[N],q1[N],q2[N];
int cnt,Ans[N];
struct BIT
{
	long long c[N];
	inline int lowbit(int x) { return x&(-x); }
	inline void Add(int x,int p)
	{
		for(;x<=m+m;x+=lowbit(x)) c[x]+=p;
	}
	inline long long Ask(int x)
	{
		long long tt=0;
		for(;x;x-=lowbit(x)) tt+=c[x];
		return tt;
	}
}A;
void Solve(int u,int v,int l,int r)
{
	if(u>v||l>r) return;
	if(l==r)
	{
		for(ri int i=u;i<=v;i++)
		if(q[i].opt==2) Ans[q[i].id]=l;
		return;
	}
	int mid=(l+r)/2;
	int tot1,tot2;
	tot1=tot2=0;
	for(ri int i=u;i<=v;i++)
	{
		if(q[i].opt==1)
		{
			if(q[i].id<=mid)
			{
				q1[++tot1]=q[i];
				A.Add(q[i].x,q[i].k), A.Add(q[i].y+1,-q[i].k);
			}
			else q2[++tot2]=q[i];
		}
		else
		{
			long long gt=0;
			for(auto j:a[q[i].x])
			{
				gt+=A.Ask(j)+A.Ask(j+m);
				if(gt>=q[i].k) break;
			}
			if(q[i].k<=gt) q1[++tot1]=q[i];
			else q[i].k-=gt, q2[++tot2]=q[i];
		}
	}
	for(ri int i=1;i<=tot1;i++)
	{
		q[u+i-1]=q1[i];
		if(q1[i].opt==1) A.Add(q1[i].x,-q1[i].k), A.Add(q1[i].y+1,q1[i].k);
	}
	for(ri int i=1;i<=tot2;i++) q[u+tot1+i-1]=q2[i];
	Solve(u,u+tot1-1,l,mid);
	Solve(u+tot1,v,mid+1,r);
}
signed main()
{
	n=read(), m=read();
	for(ri int i=1;i<=m;i++)
	{
		int x=read();
		a[x].eb(i);
	}
	for(ri int i=1;i<=n;i++) p[i]=read();
	K=read();
	for(ri int i=1;i<=K;i++)
	{
		int l,r,x;
		l=read(), r=read(), x=read();
		if(r<l) r+=m;
		cnt++, q[cnt]=(Query){l,r,x,1,cnt};
	}
	for(ri int i=1;i<=n;i++) cnt++, q[cnt]=(Query){i,i,p[i],2,cnt};
	Solve(1,cnt,1,K+1);
	for(ri int i=1;i<=cnt;i++)if(Ans[i])
	{
		if(Ans[i]==K+1) puts("NIE");
		else printf("%lld\n",Ans[i]);
	}
	return 0;
}

[HNOI2015] 接水果

整体二分 + 二维数点

#include <bits/stdc++.h>
//#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std; const int N=200010;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,P,Q,siz[N],top[N],son[N],f[N],d[N],st[N],ed[N],nowid,ta[N],pp,tb[N];
int head[N],maxE; struct Edge { int nxt,to; }e[N<<1];
inline void Add(int u,int v) { e[++maxE].nxt=head[u]; head[u]=maxE; e[maxE].to=v; }
struct Query
{
	int x,l,r,k,v,opt,id;
}q[N],q1[N],q2[N];
inline bool cp(Query x,Query y)
{
	if(x.x^y.x) return x.x<y.x;
	if(x.opt^y.opt) return x.opt<y.opt;
	return x.id<y.id;
}
struct BIT
{
	int c[N];
	inline int lowbit(int x) { return x&(-x); }
	inline void Add(int x,int p)
	{
		for(;x<=n;x+=lowbit(x)) c[x]+=p;
	}
	inline int Ask(int x)
	{
		int tt=0;
		for(;x;x-=lowbit(x)) tt+=c[x];
		return tt;
	}
}A;
int cnt,Ans[N];
void DFS1(int x,int fa)
{
	st[x]=++nowid, f[x]=fa, siz[x]=1, d[x]=d[fa]+1;
	for(ri int i=head[x];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		DFS1(v,x);
		siz[x]+=siz[v];
		if(siz[v]>siz[son[x]]) son[x]=v;
	}
	ed[x]=nowid;
}
void DFS2(int x,int topf)
{
	top[x]=topf;
	if(!son[x]) return;
	DFS2(son[x],topf);
	for(ri int i=head[x];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==f[x]||v==son[x]) continue;
		DFS2(v,v);
	}
}
inline int LCA(int x,int y)
{
	while(top[x]^top[y])
	{
		if(d[top[x]]<d[top[y]]) swap(x,y);
		x=f[top[x]];
	}
	if(d[x]>d[y]) swap(x,y);
	return x;
}
inline int GetS(int x,int y)
{
	while(top[x]^top[y])
	{
		if(f[top[x]]==y) return top[x];
		x=f[top[x]];
	}
	return son[y];
}
void Solve(int u,int v,int l,int r)
{
	if(u>v||l>r) return;
	if(l==r)
	{
		for(ri int i=u;i<=v;i++)
		if(q[i].opt==2) Ans[q[i].id]=l;
		return;
	}
	int mid=(l+r)/2;
	int tot1,tot2;
	tot1=tot2=0;
	for(ri int i=u;i<=v;i++)
	{
		if(q[i].opt==1)
		{
			if(q[i].k<=mid)
			{
				q1[++tot1]=q[i];
				A.Add(q[i].l,q[i].v), A.Add(q[i].r+1,-q[i].v);
			}
			else q2[++tot2]=q[i];
		}
		else
		{
			int gt=A.Ask(q[i].l);
			if(q[i].k<=gt) q1[++tot1]=q[i];
			else q[i].k-=gt, q2[++tot2]=q[i];
		}
	}
	for(ri int i=1;i<=tot1;i++)
	{
		q[u+i-1]=q1[i];
		if(q1[i].opt==1) A.Add(q1[i].l,-q1[i].v), A.Add(q1[i].r+1,q1[i].v);
	}
	for(ri int i=1;i<=tot2;i++) q[u+tot1+i-1]=q2[i];
	Solve(u,u+tot1-1,l,mid);
	Solve(u+tot1,v,mid+1,r);
}
signed main()
{
	n=read(), P=read(), Q=read();
	for(ri int i=1;i<n;i++)
	{
		int u,v;
		u=read(), v=read();
		Add(u,v), Add(v,u);
	}
	DFS1(1,0), DFS2(1,1);
	for(ri int i=1;i<=P;i++)
	{
		int x,y,c;
		x=read(), y=read(), c=read();
		ta[++pp]=c;
		if(st[x]>st[y]) swap(x,y);
		int lca=LCA(x,y);
		if(lca==x)
		{
			int g=GetS(y,x);
			cnt++, q[cnt]=(Query){1,st[y],ed[y],c,1,1,cnt};
			cnt++, q[cnt]=(Query){st[g],st[y],ed[y],c,-1,1,cnt};
			cnt++, q[cnt]=(Query){st[y],ed[g]+1,n,c,1,1,cnt};
			cnt++, q[cnt]=(Query){ed[y]+1,ed[g]+1,n,c,-1,1,cnt};
		}
		else
		{
			cnt++, q[cnt]=(Query){st[x],st[y],ed[y],c,1,1,cnt};
			cnt++, q[cnt]=(Query){ed[x]+1,st[y],ed[y],c,-1,1,cnt};
		}
	}
	sort(ta+1,ta+1+pp);
	pp=unique(ta+1,ta+1+pp)-ta-1;
	for(ri int i=1;i<=cnt;i++)
	{
		int x=q[i].k;
		q[i].k=lower_bound(ta+1,ta+1+pp,x)-ta;
		tb[q[i].k]=x;
	}
	for(ri int i=1;i<=Q;i++)
	{
		int x,y,k;
		x=read(), y=read(), k=read();
		if(st[x]>st[y]) swap(x,y);
		cnt++, q[cnt]=(Query){st[x],st[y],st[y],k,0,2,cnt};
	}
	sort(q+1,q+1+cnt,cp);
	Solve(1,cnt,1,pp);
	for(ri int i=1;i<=cnt;i++) if(Ans[i]) printf("%d\n",tb[Ans[i]]);
	return 0;
}

[HNOI2016] 网络

与上一题交为类似,也可以用整体二分来解决。具体的,如果询问点包含了所有大于 \(mid\) 的路径,答案小于等于 \(mid\),否则答案大于 \(mid\)

Link

#include <bits/stdc++.h>
#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std; const int N=200010;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,m,d[N],f[N],siz[N],son[N],top[N],id[N],nowid,ta[N],pp,tb[N];
int head[N],maxE; struct Edge { int nxt,to; }e[N<<1];
inline void Add(int u,int v) { e[++maxE].nxt=head[u]; head[u]=maxE; e[maxE].to=v; }
struct Query
{
	int x,y,lca,v,k,opt,id;
}q[N],q1[N],q2[N];
int cnt,Ans[N];
void DFS1(int x,int fa)
{
	d[x]=d[fa]+1, f[x]=fa, siz[x]=1;
	for(ri int i=head[x];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		DFS1(v,x);
		siz[x]+=siz[v];
		if(siz[v]>siz[son[x]]) son[x]=v;
	}
}
void DFS2(int x,int topf)
{
	top[x]=topf, id[x]=++nowid;
	if(!son[x]) return;
	DFS2(son[x],topf);
	for(ri int i=head[x];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==f[x]||v==son[x]) continue;
		DFS2(v,v);
	}
}
inline int LCA(int x,int y)
{
	while(top[x]^top[y])
	{
		if(d[top[x]]<d[top[y]]) swap(x,y);
		x=f[top[x]];
	}
	if(d[x]>d[y]) swap(x,y);
	return x;
}
struct BIT
{
	int c[N];
	inline int lowbit(int x) { return x&(-x); }
	inline void Add(int x,int p)
	{
		for(;x<=n;x+=lowbit(x)) c[x]+=p;
	}
	inline int Ask(int x)
	{
		int tt=0;
		for(;x;x-=lowbit(x)) tt+=c[x];
		return tt;
	}
}A;
void Solve(int u,int v,int l,int r)
{
	if(u>v||l>r) return;
	if(l==r)
	{
		for(ri int i=u;i<=v;i++)
		if(q[i].opt==2) Ans[q[i].id]=l;
		return;
	}
	int mid=(l+r)/2;
	int tot1,tot2;
	tot1=tot2=0;
	int now=0;
	for(ri int i=u;i<=v;i++)
	{
		if(q[i].opt==1)
		{
			if(q[i].v<=mid) q1[++tot1]=q[i];
			else
			{
				A.Add(id[q[i].x],q[i].k), A.Add(id[q[i].y],q[i].k);
				A.Add(id[q[i].lca],-q[i].k);
				if(f[q[i].lca]) A.Add(id[f[q[i].lca]],-q[i].k);
				q2[++tot2]=q[i];
				now+=q[i].k;
			}
		}
		else
		{
			int gt=A.Ask(id[q[i].x]+siz[q[i].x]-1)-A.Ask(id[q[i].x]-1);
			if(gt==now) q1[++tot1]=q[i];
			else q2[++tot2]=q[i];
		}
	}
	for(ri int i=1;i<=tot1;i++) q[u+i-1]=q1[i];
	for(ri int i=1;i<=tot2;i++)
	{
		q[u+tot1+i-1]=q2[i];
		if(q2[i].opt==1)
		{
			A.Add(id[q2[i].x],-q2[i].k), A.Add(id[q2[i].y],-q2[i].k);
			A.Add(id[q2[i].lca],q2[i].k);
			if(f[q2[i].lca]) A.Add(id[f[q2[i].lca]],q2[i].k);
		}
	}
	Solve(u,u+tot1-1,l,mid);
	Solve(u+tot1,v,mid+1,r);
}
signed main()
{
	n=read(), m=read();
	for(ri int i=1;i<n;i++)
	{
		int u,v;
		u=read(), v=read();
		Add(u,v), Add(v,u);
	}
	DFS1(1,0), DFS2(1,1);
	for(ri int i=1;i<=m;i++)
	{
		int opt=read();
		if(!opt)
		{
			int a,b,v;
			a=read(), b=read(), v=read();
			int lca=LCA(a,b);
			q[i]=(Query){a,b,lca,v,1,1,i};
			ta[++pp]=v;
		}
		else if(opt==1)
		{
			int x=read();
			if(q[x].opt==2) continue;
			q[i]=q[x];
			q[i].k=-q[i].k;
			q[i].id=i;
		}
		else
		{
			int x=read();
			q[i]=(Query){x,x,x,0,1,2,i};
		}
	}
	cnt=m;
	ta[++pp]=-1e18;
	sort(ta+1,ta+1+pp);
	pp=unique(ta+1,ta+1+pp)-ta-1;
	for(ri int i=1;i<=cnt;i++)
	{
		if(q[i].opt==1)
		{
			int x=q[i].v;
			q[i].v=lower_bound(ta+1,ta+1+pp,x)-ta;
			tb[q[i].v]=x;
		}
	}
	Solve(1,cnt,1,pp);
	for(ri int i=1;i<=cnt;i++)
	{
		if(Ans[i])
		{
			if(Ans[i]==1) puts("-1");
			else printf("%lld\n",tb[Ans[i]]);
		}
	}
	return 0;
}
posted @ 2021-02-20 19:21  zkdxl  阅读(103)  评论(0编辑  收藏  举报