题目链接:点击打开链接
题意见白书P248
思路:
先把读入的y值都扩大2倍变成整数
然后离散化一下
用线段树来维护y轴 区间上每个点的 城市数量和联通块数量,
然后用并查集维护每个联通块及联通块的最大最小y值,还要加并查集的秩来记录每个联通块的点数
然后就是模拟搞。。
T^T绝杀失败题。。似乎数组开小了一点就过了,==
#include<stdio.h> #include<math.h> #include<vector> #include<string.h> #include<algorithm> using namespace std; #define rank Rank #define L(x) (x<<1) #define R(x) (x<<1|1) #define Lson(x) tree[x].l #define Rson(x) tree[x].r #define Sum0(x) tree[x].sum[0] #define Lazy0(x) tree[x].lazy[0] #define Sum1(x) tree[x].sum[1] #define Lazy1(x) tree[x].lazy[1] inline int Mid(int x, int y){return (x+y)>>1;} #define N 100005 struct Point{ int x, y; }p[100005]; struct que{ int u, v, op; }Q[200005]; vector<int>G; int n, q; char s[10]; struct node{ int l, r, sum[2], lazy[2]; }tree[N<<4]; void push_down(int id){ if(Lazy1(id)) { Sum1(L(id)) += Lazy1(id); Sum1(R(id)) += Lazy1(id); Lazy1(L(id)) += Lazy1(id); Lazy1(R(id)) += Lazy1(id); Lazy1(id) = 0; } if(Lazy0(id)) { Sum0(L(id)) += Lazy0(id); Sum0(R(id)) += Lazy0(id); Lazy0(L(id)) += Lazy0(id); Lazy0(R(id)) += Lazy0(id); Lazy0(id) = 0; } } void push_up(int id){Sum0(id) = Sum0(L(id)) + Sum0(R(id));Sum1(id) = Sum1(L(id)) + Sum1(R(id));} void build(int l, int r, int id){ Lson(id) = l; Rson(id) = r; Sum0(id) = Lazy0(id) = Sum1(id) = Lazy1(id) = 0; if(l == r) return ; int mid = Mid(l, r); build(l, mid, L(id)); build(mid+1, r, R(id)); } void updata(int l, int r, int val, int now, int id){ push_down(id); if(l == Lson(id) && Rson(id) == r) { if(now==0)Sum0(id) += val, Lazy0(id) += val; else Sum1(id) += val, Lazy1(id) += val; return ; } int mid = Mid(Lson(id), Rson(id)); if(mid < l) updata(l, r, val, now, R(id)); else if(r <= mid) updata(l, r, val, now, L(id)); else { updata(l, mid, val, now, L(id)); updata(mid+1, r, val, now, R(id)); } push_up(id); } int query(int pos, int now, int id){ push_down(id); if(Lson(id)==Rson(id))if(now==0)return Sum0(id); else return Sum1(id); int mid = Mid(Lson(id), Rson(id)); int ans; if(mid < pos) return query(pos, now, R(id)); else return query(pos, now, L(id)); } int f[100005], rank[100005], S[100005], X[100005]; //每个集合的上下界 int find(int x){return x==f[x]?x:f[x] = find(f[x]);} void Union(int x, int y){ int fx = find(x), fy = find(y); if(fx == fy)return; if(S[fx] > S[fy]) swap(fx, fy); if(S[fx] <= X[fy]){ updata(S[fx], X[fy], 1, 0, 1); updata(S[fx], X[fy], rank[fx] + rank[fy], 1, 1); updata(X[fx], S[fx], rank[fy], 1, 1); updata(X[fy], S[fy], rank[fx], 1, 1); } else if(X[fx] >= X[fy]) { updata(X[fx], S[fx], -1, 0, 1); updata(X[fy], X[fx], rank[fx], 1, 1); updata(S[fx], S[fy], rank[fx], 1, 1); } else { updata(X[fy], S[fx], -1, 0, 1); updata(X[fx], X[fy], rank[fy], 1, 1); updata(S[fx], S[fy], rank[fx], 1, 1); } if(rank[fy]<rank[fx])swap(fx, fy); f[fx] = fy; rank[fy] += rank[fx]; rank[fx] = 0; X[fy] = min(X[fy], X[fx]); S[fy] = max(S[fy], S[fx]); } void input(){ G.clear(); scanf("%d", &n); for(int i = 1; i <= n; i++) f[i] = i, rank[i] = 1; for(int i = 1; i <= n; i++) scanf("%d %d",&p[i].x, &p[i].y), p[i].y <<= 1, G.push_back(p[i].y); scanf("%d", &q); for(int i = 0; i < q; i++) { scanf("%s", s); if(s[0]=='r') { Q[i].op = 1; scanf("%d %d", &Q[i].u, &Q[i].v); Q[i].u++; Q[i].v++; } else { Q[i].op = 2; scanf("%d.5",&Q[i].u); Q[i].u = Q[i].u * 2+1; G.push_back(Q[i].u); } } sort(G.begin(), G.end()); G.erase(unique(G.begin(), G.end()), G.end()); for(int i = 1; i <= n; i++)X[i] = S[i] = p[i].y = lower_bound(G.begin(), G.end(), p[i].y) - G.begin()+1; for(int i = 0; i < q; i++)if(Q[i].op == 2)Q[i].u = lower_bound(G.begin(), G.end(), Q[i].u) - G.begin()+1; } int main() { int T; scanf("%d",&T); while(T--){ input(); build(1, G.size(), 1); for(int i = 0; i < q; i++) { if(Q[i].op == 1) { Union(Q[i].u, Q[i].v); } else printf("%d %d\n", query(Q[i].u, 0, 1), query(Q[i].u, 1, 1)); } } return 0; } /* 3 11 1 7 5 7 8 6 3 5 5 5 2 3 10 3 7 2 4 1 11 1 4 6 21 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 line 3.5 line 2.5 line 5.5 road 10 0 line 5.5 line 6.5 road 0 3 line 1.5 line 6.5 line 2.5 ans: 0 0 2 8 1 5 2 8 3 10 1 5 1 6 1 6 2 11 1 9 2 11 */