【Codeforces 571 D】 Campus(并查集 / dfs序 / 树状数组 )

传送门

考虑这样的操作连出一颗森林
于是先离线建出树来
修改就是子树操作
只需要对于每个询问找到该点上一个被覆成 0 0 0的时间
然后对时间区间询问即可

复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

写的有点长,似乎有 2 k 2k 2k不到写完的(

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define ll long long
#define y1 shinkle
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob)?EOF:*ib++;
}
inline int read(){
    char ch=gc();
    int res=0;bool f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
inline ll readll(){
    char ch=gc();
    ll res=0;bool f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
inline int readstring(char *s){
	int top=0;char ch=gc();
	while(isspace(ch))ch=gc();
	while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
	return top;
}
template<typename tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<typename tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=1000005;
namespace Seg{
	#define lc (u<<1)
	#define rc ((u<<1)|1)
	#define mid ((l+r)>>1)
	int tag[N<<2];
	inline void pushdown(int u){
		if(!tag[u])return ;
		tag[lc]=tag[u],tag[rc]=tag[u];
		tag[u]=0;
	}
	void update(int u,int l,int r,int st,int des,int k){
		if(st<=l&&r<=des){tag[u]=k;return;}
		pushdown(u);
		if(st<=mid)update(lc,l,mid,st,des,k);
		if(mid<des)update(rc,mid+1,r,st,des,k);
	}
	int query(int u,int l,int r,int p){
		if(l==r)return tag[u];
		pushdown(u);
		if(p<=mid)return query(lc,l,mid,p);
		else return query(rc,mid+1,r,p);
	}
	#undef lc
	#undef rc
	#undef mid
}
int n,q,m,qn;
namespace Bit{
	ll tr[N];
	#define lb(x) (x&(-x))
	void update(int p,ll k){
	//cout<<"U "<<p<<'\n';
		for(;p<=m;p+=lb(p))tr[p]+=k;
		//cout<<"EDN\n";
	}
	inline ll qry(int p,ll res=0){
	//	cout<<"Q "<<p<<'\n';
		for(;p>0;p-=lb(p))res+=tr[p];
	//	cout<<"Ed\n";
		return res;
	}
	ll query(int l,int r){return qry(r)-qry(l-1);}
	#undef lb
}
ll ans[N];
vector<int> upd[N];
vector<pair<pii,int>> qr[N];
struct tree{
	int lc[N],rc[N];
	int in[N],out[N],siz[N],dfn,ff[N],tot;
	int kd;
	inline int find(int x){
		return ff[x]==x?x:ff[x]=find(ff[x]);
	}
	inline void merge(int u,int v){
		int f1=find(u),f2=find(v);
		if(f1==f2)return;
		++tot,ff[f1]=ff[f2]=ff[tot]=tot;
		lc[tot]=f1,rc[tot]=f2;
	}
	inline void init(){tot=n;
		for(int i=1;i<=n;i++)ff[i]=i;
	}
	void dfs(int u){
		in[u]=++dfn;siz[u]=(u<=n);
		if(lc[u])dfs(lc[u]),siz[u]+=siz[lc[u]];
		if(rc[u])dfs(rc[u]),siz[u]+=siz[rc[u]];
		out[u]=dfn;
	}
	void build(){
		for(int i=1;i<=tot;i++)if(ff[i]==i)dfs(i);
	}
	void update(int u,int i){
		Seg::update(1,1,tot,in[u],out[u],i);
	}
	int query(int u){
		return Seg::query(1,1,tot,in[u]);
	}
	void dfs2(int u){
		for(int &x:upd[u])
		Bit::update(x,siz[u]);
		for(pair<pii,int> &x:qr[u])
		ans[x.se]=Bit::query(x.fi.fi,x.fi.se);
		if(lc[u])dfs2(lc[u]);
		if(rc[u])dfs2(rc[u]);
		for(int &x:upd[u])
		Bit::update(x,-siz[u]);		
	}
	void solve(){
		for(int i=1;i<=tot;i++)if(ff[i]==i)dfs2(i);
	}
}t1,t2;
struct opt{
	int op,x;
	opt(int a=0,int b=0):op(a),x(b){}
}p[N];
char str[3];
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
	n=read(),q=read();
	t1.init(),t2.init();
	for(int i=1,x,y;i<=q;i++){
		readstring(str);
		switch(str[1]){
			case 'U':x=read(),y=read(),t1.merge(x,y);break;
			case 'M':x=read(),y=read(),t2.merge(x,y);break;
			case 'A':x=read(),p[++m]=opt(1,t1.find(x));break;
			case 'Z':x=read(),p[++m]=opt(2,t2.find(x));break;
			case 'Q':x=read(),p[++m]=opt(3,x);break;
		}
	}
	t1.build(),t2.build();
	for(int i=1;i<=m;i++){
		switch(p[i].op){
			case 1:upd[p[i].x].pb(i);;break;
			case 2:t2.update(p[i].x,i);break;
			case 3:qr[p[i].x].pb(make_pair(pii(t2.query(p[i].x),i),++qn));break;
		}
	}
	t1.solve();
	for(int i=1;i<=qn;i++)cout<<ans[i]<<'\n';
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值