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
",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;
}

  

原文地址:https://www.cnblogs.com/clrs97/p/4403166.html