Codeforces 1195F Geometers Anonymous Club

可以写树状数组,这里直接写的线段树

#include<bits/stdc++.h>
using namespace std; const int N = 1e5 + 10;
struct SegmentTree {
    int l, r, sum, f;
    #define l(x) Tree[x].l
    #define r(x) Tree[x].r
    #define sum(x) Tree[x].sum
    #define f(x) Tree[x].f
} Tree[N * 4];
void build(int p, int l, int r) {
    l(p) = l, r(p) = r;
    if (l == r)return; int mid = (l + r) / 2;
    build(p * 2, l, mid); build(p * 2 + 1, mid + 1, r);
}
void spread(int x) {
    sum(x * 2) += f(x) * (r(x * 2) - l(x * 2) + 1);
    sum(x * 2 + 1) += f(x) * (r(x * 2 + 1) - l(x * 2 + 1) + 1);
    f(x * 2) += f(x); f(x * 2 + 1) += f(x); f(x) = 0;
}
void add(int p, int l, int r, int val) {
    if (l > r)return;
    if (l <= l(p) && r >= r(p)) {sum(p) += (r(p) - l(p) + 1) * val; f(p) += val;; return;}
    if (f(p) != 0)spread(p);
    int mid = (l(p) + r(p)) / 2;
    if (l <= mid)add(p * 2, l, r, val); if (r > mid)add(p * 2 + 1, l, r, val);
}
int ask(int p, int x) {
    if (x == 0)return 0;
    if (l(p) == r(p))return sum(p); if (f(p) != 0)spread(p); int mid = (l(p) + r(p)) / 2;
    if (x <= mid)return ask(p * 2, x); else return ask(p * 2 + 1, x);
}
array<int, 2> Hash(int x, int y) {
    int G = __gcd(abs(x), abs(y)); return{x / G, y / G};
}
vector<array<int, 2> > input() {
    int n; cin >> n; vector<array<int, 2> >A(n); vector<array<int, 2> > B;
    for (auto&i : A)cin >> i[0] >> i[1]; A.push_back(A[0]);
    for (int i = 1; i <= n; ++i)B.push_back(Hash(A[i][0] - A[i - 1][0], A[i][1] - A[i - 1][1]));
    return B;
}
int main() {
    int n, x, y; cin >> n; vector<vector<array<int, 2> > > A(n + 10); map<array<int, 2>, int> M;
    for (int i = 1; i <= n; ++i)A[i] = input();
    vector<vector<array<int, 2> > >B(n + 10);
    int q; cin >> q; vector<int> ANS(q + 10); for (int i = 1; i <= q; ++i) {cin >> x >> y; B[y].push_back({x, i});}
    build(1, 1, n + 10);
    for (int i = 1; i <= n; ++i) {
        for (int j = 0; j < A[i].size(); ++j) {
            if (M[A[i][j]] != 0)add(1, M[A[i][j]], i-1, -1);
            M[A[i][j]] = i;
        }
        add(1, i, i, ask(1, i-1) + A[i].size());
        for (auto&j : B[i]) ANS[j[1]] = ask(1, i) - ask(1, j[0] - 1);
    }
    for (int i = 1; i <= q; ++i)cout << ANS[i] << endl;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值