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;

}

  

 

你可能感兴趣的:(love)