Description
若一个点集为S,记
E
(
S
)
=
{
(
x
2
,
y
2
)
∣
(
x
1
,
y
1
)
∈
S
,
(
x
1
,
y
2
)
∈
S
,
(
x
2
,
y
1
)
∈
S
,
(
x
2
,
y
2
)
∉
S
}
E(S)=\left\{(x_2,y_2)|\right (x_1,y_1)\in S,(x1,y2)\in S,(x2,y1)\in S,(x2,y2)\notin S\}
E(S)={(x2,y2)∣(x1,y1)∈S,(x1,y2)∈S,(x2,y1)∈S,(x2,y2)∈/S}
要求资瓷Q次操作向S中插入一个元素、删除一个元素,每次操作后求出
∣
E
(
S
)
∣
|E(S)|
∣E(S)∣
Q
≤
3
×
1
0
5
∀
x
,
y
≤
3
×
1
0
5
Q\le 3\times10^5\\ \forall x,y\le3\times10^5
Q≤3×105∀x,y≤3×105
Solution
很巧妙啊
我们把x坐标或y坐标相同的点放在一个集合里面,那么一个集合的贡献就是这个集合里x的值域*y的值域
具体实现的话就是把点(x,y)看成连接x和y的一条边,那么就可以用并查集维护值域这个东西了。由于需要删除和插入我们套一个线段树分治就行了
原来CF开%lld要用c++17,我火星了。。
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <stack>
#include <map>
#define rep(i,st,ed) for (register int i=st;i<=ed;++i)
#define fi first
#define se second
typedef std:: pair <int,int> pair;
typedef long long LL;
const int N=300005;
std:: vector <pair> vec[N<<2];
std:: map <pair,int> map;
std:: stack <pair> stack;
LL sx[N*2+5],sy[N*2+5],ans;
int fa[N*2+5];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
int find(int x) {
return (!fa[x])?x:find(fa[x]);
}
void modify(int now,int tl,int tr,int l,int r,pair v) {
if (tl>=l&&tr<=r) return (void) (vec[now].push_back(v));
int mid=(tl+tr)>>1;
if (l<=mid) modify(now<<1,tl,mid,l,r,v);
if (mid+1<=r) modify(now<<1|1,mid+1,tr,l,r,v);
}
void solve(int now,int tl,int tr) {
LL rec=ans; int wjp=stack.size();
for (int i=0;i<vec[now].size();++i) {
int x=vec[now][i].fi,y=vec[now][i].se+N;
x=find(x),y=find(y);
if (x==y) continue;
if (sx[x]+sy[x]>sx[y]+sy[y]) std:: swap(x,y);
ans-=sx[x]*sy[x]+sx[y]*sy[y];
fa[x]=y; sx[y]+=sx[x]; sy[y]+=sy[x];
ans+=sx[y]*sy[y];
stack.push(pair(x,y));
}
if (tl!=tr) {
int mid=(tl+tr)>>1;
solve(now<<1,tl,mid);
solve(now<<1|1,mid+1,tr);
} else printf("%lld\n", ans);
ans=rec;
for (;stack.size()>wjp;) {
pair tmp=stack.top(); stack.pop();
int x=tmp.fi,y=tmp.se;
fa[x]=0; sx[y]-=sx[x],sy[y]-=sy[x];
}
}
int main(void) {
//freopen("data.in","r",stdin);
int n=read();
rep(i,1,n) {
int x=read(),y=read();
pair now=pair(x,y);
if (map[now]) {
modify(1,1,n,map[now],i-1,now);
map.erase(map.find(now));
} else map[now]=i;
}
for (auto item: map) {
modify(1,1,n,item.se,n,item.fi);
}
rep(i,1,N) fa[i]=0,sx[i]=1;
rep(i,1,N) fa[i+N]=0,sy[i+N]=1;
solve(1,1,n);
return 0;
}