有 $q$ 次操作,每次操作:1.加入一个整点。2.删除一个整点。3.询问以一条 $y\over x$ 为斜率过原点的线为对称轴,需要添加多少个点使得所有点都有对称点。
一直在推式子……发现考虑下几何意义(看下题解和AC代码)就行了……如果两个点 $(x_1,y_1),(x_2,y_2)$ 与原点的距离相同,那么这两个点的连线就是他们对称轴的中垂线。
记 $S(l)$ 表示以 $l$ 为对称轴配对点的个数,也就是说 $(x_1,y_1),(x_2,y_2),x_1^2+y_1^2=x_2^2+y_2^2$ 对 $S({y_1+y_2\over x_1+x_2})$ 有贡献。
因为可以爆枚发现 $x^2+y^2=A$ 的解在 $A\le 10^{10}$ 的情况下最多只有 $O(100)$ 组解,所以复杂度是正常的。
再记录 $L(l)$ 表示在 $l$ 上的点的个数,每次询问的答案就是 $n-2S(l)-L(l)$ 。
吃我map
套set
树套树。
#include<cstdio>
#include<algorithm>
#include<map>
#include<set>
#define fr first
#define sc second
#define mp make_pair
using namespace std;
typedef long long LL;typedef pair<int,int> data;
int te,n;map<data,int> L,S;map<LL, set<data> > P;set<data>::iterator it;
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
inline data Line(int x,int y) {int t=gcd(x,y);return mp(x/t,y/t);}
int main(){
freopen("program.in","r",stdin);freopen("program.out","w",stdout);
for (int td=scanf("%d",&te),x,y;te;te--){
scanf("%d%d%d",&td,&x,&y);LL val=(LL)x*x+(LL)y*y;
if (td==1){
for (it=P[val].begin();it!=P[val].end();it++) S[Line((*it).fr+x,(*it).sc+y)]++;
L[Line(x,y)]++;P[val].insert(mp(x,y));n++;
} else if (td==2) {
L[Line(x,y)]--;P[val].erase(mp(x,y));n--;
for (it=P[val].begin();it!=P[val].end();it++) S[Line((*it).fr+x,(*it).sc+y)]--;
} else printf("%d\n",n-L[Line(x,y)]-2*S[Line(x,y)]);
}
return 0;
}