洛谷传送门
Codeforces传送门
题目大意
给你一个 n n n个点 m m m条边的无向图, 任意一条边 a i → b i a_i\to b_i ai→bi满足 ∣ a i − b i ∣ ≤ k |a_i-b_i|\le k ∣ai−bi∣≤k,给出 q q q组询问, 每次询问 [ l , r ] [l,r] [l,r]内节点构成的子图的连通块个数。
输入输出格式
输入格式
第一行三个正整数 n , m , k n,m,k n,m,k。
以下 m m m行, 每行两个正整数 a i , b i a_i,b_i ai,bi。
以下一行一个正整数 q q q。
下面 q q q行, 每行两个正整数 l i , r i l_i, r_i li,ri表示一组询问。
输出格式
对于每组询问, 输出一个正整数表示连通块个数。
输入输出样例
输入样例#1:
5 3
3
1 3
2 3
4 5
5
1 1
1 2
2 3
1 3
1 5
输出样例#1:
1
2
1
1
2
解题分析
还以为 k k k有什么用… 直接 L C T LCT LCT大力搞就好了啊。
对所有边和询问按右端点排序, 然后维护最大生成树, 定义一条边的权值为两端点编号较小的那个, 用树状数组维护权值出现的次数, 查询直接查权值 ≥ l \ge l ≥l的生成树上的边有几条。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <climits>
#include <cctype>
#include <cstdlib>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define MX 600500
#define gc getchar()
#define ls tree[now].son[0]
#define rs tree[now].son[1]
#define lbt(i) ((i) & (-(i)))
#define dad tree[now].fat
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
int n, m, cnt, top, k, q, tot;
struct Node {int son[2], fat, val, mn, pos; bool rev;} tree[MX];
struct OPT {int l, r, id;} edge[MX], que[MX];
int fr[MX], to[MX], sta[MX], ans[MX], Tree[MX];
IN bool operator < (const OPT &x, const OPT &y) {return x.r < y.r;}
IN void add(R int pos, R int del)
{for (; pos <= n; pos += lbt(pos)) Tree[pos] += del;}
IN int query(R int pos)
{
int ret = 0;
for (; pos; pos -= lbt(pos)) ret += Tree[pos];
return ret;
}
IN bool get(R int now) {return tree[dad].son[1] == now;}
IN bool nroot(R int now) {return tree[dad].son[1] == now || tree[dad].son[0] == now;}
IN void pushup(R int now)
{
tree[now].pos = now, tree[now].mn = tree[now].val;
if (ls) if (tree[ls].mn < tree[now].mn) tree[now].mn = tree[ls].mn, tree[now].pos = tree[ls].pos;
if (rs) if (tree[rs].mn < tree[now].mn) tree[now].mn = tree[rs].mn, tree[now].pos = tree[rs].pos;
}
IN void pushrev(R int now) {std::swap(ls, rs), tree[now].rev ^= 1;}
IN void pushdown(R int now)
{
if (tree[now].rev)
{
pushrev(ls), pushrev(rs);
tree[now].rev = false;
}
}
IN void rotate(R int now)
{
R bool dir = get(now);
R int fa = dad, grand = tree[fa].fat;
tree[fa].son[dir] = tree[now].son[dir ^ 1];
tree[tree[now].son[dir ^ 1]].fat = fa;
tree[now].fat = grand;
if (nroot(fa)) tree[grand].son[get(fa)] = now;
tree[fa].fat = now;
tree[now].son[dir ^ 1] = fa;
pushup(fa);
}
IN void splay(R int now)
{
int tmp = sta[top = 1] = now, fa;
W (nroot(now)) sta[++top] = now = dad;
W (top) pushdown(sta[top--]);
now = tmp;
W (nroot(now))
{
fa = dad;
if (nroot(fa)) rotate(get(now) == get(fa) ? fa : now);
rotate(now);
}
pushup(now);
}
IN void access(R int now)
{
for (R int x = 0; now; x = now, now = dad)
splay(now), rs = x, pushup(now);
}
IN void makeroot(R int now) {access(now), splay(now), pushrev(now);}
IN void split(R int x, R int y) {makeroot(x); access(y); splay(y);}
IN void link(R int x, R int y) {makeroot(x); tree[x].fat = y;}
IN void cut(R int x, R int y)
{
split(x, y);
tree[x].fat = tree[y].son[0] = 0;
pushup(y);
}
IN int findroot(R int now)
{
access(now), splay(now);
W (ls) pushdown(now), now = ls;
return now;
}
int main(void)
{
int foo, bar, tar;
in(n), in(k), in(m); cnt = n;
for (R int i = 1; i <= n; ++i) tree[i].val = tree[i].mn = INT_MAX;
for (R int i = 1; i <= m; ++i)
{
in(edge[i].l), in(edge[i].r);
if (edge[i].l > edge[i].r) std::swap(edge[i].l, edge[i].r);
}
in(q);
for (R int i = 1; i <= q; ++i) in(que[i].l), in(que[i].r), que[i].id = i;
std::sort(edge + 1, edge + 1 + m);
std::sort(que + 1, que + 1 + q);
R int cur = 1;
for (R int i = 1; i <= q; ++i)
{
W (cur <= m && edge[cur].r <= que[i].r)
{
foo = findroot(edge[cur].l), bar = findroot(edge[cur].r);
if (foo ^ bar)
{
++cnt;
tree[cnt].val = tree[cnt].mn = edge[cur].l;
link(edge[cur].l, cnt), link(edge[cur].r, cnt);
fr[cnt] = edge[cur].l, to[cnt] = edge[cur].r;
add(edge[cur].l, 1); ++tot;
}
else
{
split(edge[cur].l, edge[cur].r);
tar = tree[edge[cur].r].pos;
if (tree[edge[cur].r].mn < edge[cur].l)
{
cut(tar, fr[tar]), cut(tar, to[tar]);
add(fr[tar], -1);
++cnt;
tree[cnt].val = tree[cnt].mn = edge[cur].l;
link(edge[cur].l, cnt), link(edge[cur].r, cnt);
fr[cnt] = edge[cur].l, to[cnt] = edge[cur].r;
add(edge[cur].l, 1);
}
}
++cur;
}
ans[que[i].id] = que[i].r - que[i].l + 1 - (tot - query(que[i].l - 1));
}
for (R int i = 1; i <= q; ++i) printf("%d\n", ans[i]);
}
PS:此题貌似有 N k Nk Nk做法? 不是很懂…