BZOJ3847 : ZCC loves march
注意到集结操作相当于合并一些点
于是我们可以使用并查集
对于每一行、每一列维护一个链表,储存里面的点
查询x时,在并查集中找到x的祖先u,此时x的坐标就是u的坐标
然后扫描u所在行列的链表,依次删除每个点,并把这些点合并成一个新点,同时计算贡献
对于修改操作,可以看作是分离,新建一个点代表修改后的点,然后对于原来的点减掉贡献即可
#include<cstdio> #include<map> #define N 300010 #define P 1000000007 typedef long long ll; int n,m,i,id,f[N],C[N],tot,x,y,g[N<<1],nxt[N<<1],v[N<<1],ed,cnt,u; ll X[N],Y[N],d,nx,ny,ans; bool del[N]; std::map<ll,int>locx,locy; char op[5]; inline ll sqr(ll x){x%=P;return x*x%P;} inline int posx(ll x){return locx[x]?locx[x]:locx[x]=++cnt;} inline int posy(ll y){return locy[y]?locy[y]:locy[y]=++cnt;} inline void addedge(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} inline void addset(int x){addedge(posx(X[x]),x),addedge(posy(Y[x]),x);} inline void addnode(ll x,ll y,int c){X[++tot]=x,Y[tot]=y,C[tot]=c,f[tot]=tot;} inline int F(int x){return f[x]==x?x:f[x]=F(f[x]);} int main(){ scanf("%d%lld",&n,&nx); for(i=1;i<=n;i++)scanf("%lld%lld",&nx,&ny),addnode(nx,ny,1); for(i=1;i<=n;i++)addnode(X[i],Y[i],1),addset(tot),f[i]=tot; scanf("%d",&m); while(m--){ scanf("%s%d",op,&x);u=F(x^=ans); if(op[0]=='Q'){ addnode(X[u],Y[u],ans=0); for(i=g[id=locx[X[u]]];i;i=nxt[i])if(!del[v[i]])del[v[i]]=1,(ans+=sqr(Y[v[i]]-Y[u])*C[v[i]])%=P,C[tot]+=C[v[i]],f[v[i]]=tot; g[id]=0,addedge(id,tot); for(i=g[id=locy[Y[u]]];i;i=nxt[i])if(!del[v[i]])del[v[i]]=1,(ans+=sqr(X[v[i]]-X[u])*C[v[i]])%=P,C[tot]+=C[v[i]],f[v[i]]=tot; g[id]=0,addedge(id,tot); printf("%lld\n",ans); }else{ scanf("%lld",&d);nx=X[u],ny=Y[u]; if(op[0]=='U')nx-=d; if(op[0]=='D')nx+=d; if(op[0]=='L')ny-=d; if(op[0]=='R')ny+=d; C[u]--,addnode(nx,ny,1),addset(f[x]=tot); } } return 0; }