题意:
给你n 个城市,初始时,没有任何双向道路相连接。
两种操作:
1. 将A点和B点连接。
2.询问一条y = C的水平线 和多少个连通块 多少个点连接。
思路:
因为询问只是涉及到y 坐标。并且数据较大。
我们直接存下所有的y 坐标 离散化一下。
然后就可以建立线段树了。
线段树维护两个值 一个时连通块个数,一个是点的个数。
操作1 ,我们维护每个连通块 y 坐标最大和最小。 然后就是区间增减问题了。(注意交集的问题。)
操作2 直接对应输出即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100000 + 10;
int T, n, m;
double a[maxn<<2];
int cnt;
int siz[maxn]; /// 连通块大小。
int fa[maxn];
int find(int x){
return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
}
double Max[maxn], Min[maxn];
int get(double x){ /// 二分找离散化的值。
int l = 0, r = cnt - 1, m;
while(l <= r){
m = l + r >> 1;
if (a[m] == x) return m;
else if (a[m] > x) r = m - 1;
else l = m + 1;
}
}
struct Point{
double x,y;
void read(){
scanf("%lf %lf",&x, &y);
}
}p[maxn];
struct QUERY{
int op;
int u,v;
double x;
}q[maxn<<1];
char cmd[20];
struct node{
int l,r;
long long city, state;
int addc, adds;
}nod[maxn<<4];
void pushup(int o){
int lson = o << 1;
int rson = o << 1 | 1;
nod[o].city = nod[lson].city + nod[rson].city;
nod[o].state = nod[lson].state + nod[rson].state;
}
void pushdown(int o){
int l = nod[o].l;
int r = nod[o].r;
if (l == r) return;
int m = l + r >> 1;
if (nod[o].addc){
int lson = o << 1;
int rson = o << 1 | 1;
nod[lson].addc += nod[o].addc;
nod[rson].addc += nod[o].addc;
nod[lson].city += (long long)nod[o].addc * (m-l+1);
nod[rson].city += (long long)nod[o].addc * (r-m);
nod[o].addc = 0;
}
if (nod[o].adds){
int lson = o << 1;
int rson = o << 1 | 1;
nod[lson].adds += nod[o].adds;
nod[rson].adds += nod[o].adds;
nod[lson].state += (long long)nod[o].adds * (m-l+1);
nod[rson].state += (long long)nod[o].adds * (r-m);
nod[o].adds = 0;
}
}
void build(int l,int r,int o){
nod[o].l = l;
nod[o].r = r;
nod[o].city = nod[o].state = 0;
nod[o].addc = nod[o].adds = 0;
if (l == r) return;
int m = l + r >> 1;
build(l, m, o << 1);
build(m+1,r,o << 1 | 1);
}
long long ans1, ans2;
void query(int L,int R,int l,int r, int o){
if (L <= l && r <= R){
ans1 = nod[o].state;
ans2 = nod[o].city;
return;
}
pushdown(o);
int m = l + r >> 1;
if (m >= L){
query(L, R, l, m, o<<1);
}
if (m < R){
query(L, R, m+1, r, o<<1|1);
}
}
void update_city(int L,int R,int c,int l,int r, int o){ /// 更新点
if (L <= l && r <= R){
nod[o].addc += c;
nod[o].city += c * (r-l+1);
return;
}
pushdown(o);
int m = l + r >> 1;
if (m >= L){
update_city(L, R, c, l, m, o<<1);
}
if (m < R){
update_city(L, R, c, m+1, r, o<<1|1);
}
pushup(o);
}
void update_state(int L,int R,int c,int l,int r, int o){ /// 更新连通块
if (L <= l && r <= R){
nod[o].adds += c;
nod[o].state += c * (r-l+1);
return;
}
pushdown(o);
int m = l + r >> 1;
if (m >= L){
update_state(L, R, c, l, m, o<<1);
}
if (m < R){
update_state(L, R, c, m+1, r, o<<1|1);
}
pushup(o);
}
int main(){
scanf("%d",&T);
while(T--){
cnt = 0;
scanf("%d",&n);
for (int i = 0; i < n; ++i){
p[i].read();
fa[i] = i;
Max[i] = Min[i] = p[i].y;
siz[i] = 1;
a[cnt++] = p[i].y;
}
scanf("%d",&m);
for (int i = 0; i < m; ++i){
scanf("%s", cmd);
if (cmd[0] == 'r'){
scanf("%d%d",&q[i].u, &q[i].v);
q[i].op = 0;
}
else {
scanf("%lf", &q[i].x);
q[i].op = 1;
a[cnt++] = q[i].x;
}
}
sort(a, a+cnt); /// 离散化y坐标。
cnt = unique(a, a + cnt) - a;
build(0, cnt-1, 1);
for (int i = 0; i < n; ++i){
int id = get(p[i].y);
update_city(id, id, 1, 0, cnt-1, 1);
update_state(id, id, 1, 0, cnt-1, 1);
}
for (int i = 0; i < m; ++i){
if (q[i].op == 1){
int id = get(q[i].x);
query(id, id, 0, cnt-1, 1);
printf("%lld %lld\n", ans1, ans2);
}
else {
int x = q[i].u;
int y = q[i].v;
if (find(x) == find(y)) continue;
int fx = find(x), fy = find(y);
int LY = get(Min[fx]), RY = get(Max[fx]); ///单独处理
update_city(LY, RY, siz[fy], 0, cnt-1, 1);
LY = get(Min[fy]); RY = get(Max[fy]); ///单独处理。
update_city(LY, RY, siz[fx], 0, cnt-1, 1);
double miny = min(Max[fx], Max[fy]);
double maxy = max(Min[fx], Min[fy]);
if (Min[fx] > Max[fy] || Min[fy] > Max[fx]){ /// 没有交集的话,直接修改。
double low = min(Max[fx], Max[fy]);
double high = max(Min[fx], Min[fy]);
int id1 = get(low);
int id2 = get(high);
// printf("jjjjjjj %.3f %.3f\n", low, high);
if (id1+1<=id2-1){
update_state(id1+1, id2-1, 1, 0, cnt-1, 1);
update_city(id1+1 ,id2-1, (siz[fx] + siz[fy]), 0, cnt-1, 1);
}
}
else { /// 有交集 要减去加重的部分。
int id1 = get(maxy);
int id2 = get(miny);
// printf("hhh %d %d\n", id1, id2);
update_state(id1, id2, -1, 0, cnt-1, 1);
update_city(id1 ,id2, -(siz[fx] + siz[fy]), 0, cnt-1, 1);
}
fa[fy] = fx;
siz[fx] += siz[fy];
Max[fx] = max(Max[fy], Max[fx]);
Min[fx] = min(Min[fy], Min[fx]);
}
}
}
return 0;
}
/**
My test!
3
3
2 3
3 5
4 1
5
line 3
road 0 1
line 4
road 1 2
line 3
================
3
10
1 7
5 7
8 6
3 5
5 5
2 3
10 3
7 2
4 1
11 1
11
road 0 1
road 3 5
line 6.5
road 4 2
road 3 8
road 4 7
road 6 9
road 4 1
road 2 7
line 4.5
line 6.5
1
100 100
1
line 100.5
2
10 10
20 20
2
road 0 1
line 15.5
ans:
0 0
2 8
1 5
0 0
1 2
**/