题目
首先离线,对于操作一、三和操作二、四,分别建出两棵 Kruskal 重构树。
然后问题就转化成在两棵树上分别做子树加一个值和子树赋值的操作。
我们先用一次树上 dfs 处理出每次询问的那个在点在询问时刻之前最后一次被赋值为
0
0
0 的时刻。具体地,dfs 每经过一个点时就在所有以这个点为根的子树的赋值操作的时刻上打 tag
,然后对于每一个询问在数据结构上二分即可。这里可以选择树状数组二分或线段树二分。
得到每个询问的点最后一次赋值的时刻后,问题进一步转化成区间求和,再做一遍类似上面的树上 dfs 即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
#define int long long
#define lc note<<1
#define rc note<<1|1
using namespace std;
const int N=1e6+5;
int n,m,tot1,tot2,x,y,pos;
char opt[5];
int fa1[N],fa2[N],cnt[N],ans[N],las[N];
bool vis[N];
vector<int> c1[N],c2[N],q[N];
inline int read()
{
int s=0,t=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
return s*t;
}
struct node
{
int lson,rson;
}tree1[N],tree2[N];
inline int find1(int s){return fa1[s]==s?s:(fa1[s]=find1(fa1[s]));}
inline int find2(int s){return fa2[s]==s?s:(fa2[s]=find2(fa2[s]));}
struct BIT
{
int c[N];
inline void add(int a,int b){for(int i=a+1;i<=m;i+=i&(-i))c[i]+=b;}
inline int query(int a){int res=0;for(int i=a+1;i;i-=i&(-i))res+=c[i];return res;}
inline int query(int a,int b){return query(b)-query(a-1);}
}B;
inline void dfs1(int u)
{
vis[u]=1;
int sz=c1[u].size();
for(int i=0;i<sz;++i)
{
int tim=c1[u][i];
B.add(tim,cnt[u]);
}
int siz=q[u].size();
for(int i=0;i<siz;++i)
{
int id=q[u][i];
ans[id]=B.query(las[id]+1,id-1);
}
if(tree1[u].lson) dfs1(tree1[u].lson);
if(tree1[u].rson) dfs1(tree1[u].rson);
for(int i=0;i<sz;++i)
{
int tim=c1[u][i];
B.add(tim,-cnt[u]);
}
return;
}
struct sgt
{
struct Tree
{
int sum;
}s[N<<2];
inline void push_up(int note){s[note].sum=s[lc].sum+s[rc].sum;}
inline void modify(int note,int l,int r,int pos,int val)
{
if(l==r){s[note].sum=val;return;}
int mid=(l+r)>>1;
if(pos<=mid) modify(lc,l,mid,pos,val);
else modify(rc,mid+1,r,pos,val);
push_up(note);
return;
}
inline int calc(int note,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr) return s[note].sum;
int mid=(l+r)>>1,res=0;
if(ql<=mid) res+=calc(lc,l,mid,ql,qr);
if(qr>mid) res+=calc(rc,mid+1,r,ql,qr);
return res;
}
inline int query(int note,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)
{
if(l==r)
{
if(s[note].sum) return l;
return 0;
}
int mid=(l+r)>>1;
if(s[rc].sum) return query(rc,mid+1,r,ql,qr);
else return query(lc,l,mid,ql,qr);
}
int mid=(l+r)>>1;
if(qr>mid&&calc(rc,mid+1,r,ql,qr)) return query(rc,mid+1,r,ql,qr);
else if(ql<=mid) return query(lc,l,mid,ql,qr);
return 0;
}
}T;
inline void dfs2(int u)
{
vis[u]=1;
int sz=c2[u].size();
for(int i=0;i<sz;++i)
{
int tim=c2[u][i];
T.modify(1,1,m,tim,1);
}
if(u<=n)
{
int siz=q[u].size();
for(int i=0;i<siz;++i)
{
int id=q[u][i];
las[id]=T.query(1,1,m,1,id);
}
}
if(tree2[u].lson) dfs2(tree2[u].lson);
if(tree2[u].rson) dfs2(tree2[u].rson);
for(int i=0;i<sz;++i)
{
int tim=c2[u][i];
T.modify(1,1,m,tim,0);
}
}
signed main()
{
n=read();
m=read();
for(int i=1;i<=n;++i) fa1[i]=i,fa2[i]=i,cnt[i]=1;
tot1=tot2=n;
for(int i=1;i<=m;++i)
{
scanf("%s",opt+1);
if(opt[1]=='U')
{
x=read();
y=read();
++tot1;
fa1[tot1]=tot1;
tree1[tot1].lson=find1(x);
tree1[tot1].rson=find1(y);
cnt[tot1]=cnt[find1(x)]+cnt[find1(y)];
fa1[find1(x)]=fa1[find1(y)]=tot1;
}
if(opt[1]=='M')
{
x=read();
y=read();
++tot2;
fa2[tot2]=tot2;
tree2[tot2].lson=find2(x);
tree2[tot2].rson=find2(y);
fa2[find2(x)]=fa2[find2(y)]=tot2;
}
if(opt[1]=='A')
{
pos=read();
c1[find1(pos)].push_back(i);
}
if(opt[1]=='Z')
{
pos=read();
c2[find2(pos)].push_back(i);
}
if(opt[1]=='Q')
{
pos=read();
q[pos].push_back(i);
}
}
for(int i=tot2;i;--i)
if(!vis[i]) dfs2(i);
for(int i=1;i<=m;++i) ans[i]=-1;
for(int i=1;i<=tot1;++i) vis[i]=0;
for(int i=tot1;i;--i)
if(!vis[i]) dfs1(i);
for(int i=1;i<=m;++i)
if(ans[i]!=-1) printf("%lld\n",ans[i]);
return 0;
}