• 【bzoj4753】【uoj#195】【LOJ2092】【ZJOI2016】大森林


    显然0操作的时候可以当做所有树都加了这么一个点(但是后面挂到这个点的1操作的区间要对这个区间取min),这样0和2操作都跟时间没有关系了。
    可以对每个1操作建一个虚点,点权为0,然后从它到下一个1操作间的所有0操作都可以连到这个虚点。虚点先默认连向上一次1操作,一边从左到右扫一边把1操作连到对应的点或者把它连回上一个1操作,这样就可以用LCT维护出所有位置的树。
    但是这样查询的时候是会出锅的。查两个点距离的时候,如果我们直接split,可能会把一个虚点当做lca,实际上还要走到上面第一个实点。
    其实有根树的LCT上是可以求lca的,access的时候返回最后转到根的那个点,求的时候access(x),然后access(y)返回的点就是lca(因为lca肯定是最后一个被access的点)。
    我代码写得真是太shit了。。。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int mxn=262144;
    int rd(){
    	int x=0;
    	char c=getchar();
    	for (;c<48||c>57;c=getchar());
    	for (;c>47&&c<58;x=x*10+c-48,c=getchar());
    	return x;
    }
    struct nd{
    	int sum;
    	bool cnt,tag;
    	nd *ls,*rs,*fa;
    }pool[mxn],*tpp=pool,*id[mxn],*stk[mxn];
    bool noroot(nd *i){
    	return i->fa&&(i->fa->ls==i||i->fa->rs==i);
    }
    void pushup(nd *i){
    	i->sum=i->cnt;
    	if (i->ls) i->sum+=i->ls->sum;
    	if (i->rs) i->sum+=i->rs->sum;
    }
    void reverse(nd *i){
    	if (i) swap(i->ls,i->rs),i->tag^=1;
    }
    void pushdown(nd *i){
    	if (i->tag) i->tag=0,reverse(i->ls),reverse(i->rs);
    }
    void rotate(nd *i){
    	nd *f=i->fa,*s;
    	if (noroot(f))
    		if (f->fa->ls==f) f->fa->ls=i;
    		else f->fa->rs=i;
    	else;
    	i->fa=f->fa,f->fa=i;
    	if (f->ls==i) f->ls=s=i->rs,i->rs=f;
    	else f->rs=s=i->ls,i->ls=f;
    	if (s) s->fa=f;
    	pushup(f),pushup(i);
    }
    void splay(nd *x,int tp=1){
    	stk[1]=x;
    	for (nd *y=x;noroot(y);stk[++tp]=y=y->fa);
    	for (;tp;pushdown(stk[tp--]));
    	for (nd *y;noroot(x);rotate(x))
    		if (noroot(y=x->fa)) rotate((y->ls==x)^(y->fa->ls==y)?x:y);
    }
    nd *access(nd *x,nd *y=0){
    	for (;x;x=(y=x)->fa)
    		splay(x),x->rs=y,pushup(x);
    	return y;
    }
    void link(nd *x,nd *y){
    	splay(x),x->fa=y;
    }
    void cut(nd *x,nd *y){
    	access(y),splay(y),splay(x),x->fa=0;
    }
    int n,m,q,tot,k,lb[mxn],rb[mxn],cr[mxn],ty[mxn],ans[mxn];
    struct node{
    	int id,pos,x,y,z;
    }a[mxn];
    bool operator<(const node x,const node y){
    	return x.pos<y.pos||(x.pos==y.pos&&x.id<y.id);
    }
    int main()
    {
    	m=rd(),q=rd();
    	lb[1]=1,rb[1]=m,id[1]=++tpp;
    	n=1,m=0;
    	tpp->sum=tpp->cnt=1;
    	for (int i=1;i<=q;++i){
    		int typ=rd();
    		if (!typ){
    			id[++n]=++tpp,tpp->sum=tpp->cnt=1;
    			lb[n]=rd(),rb[n]=rd();
    		}
    		else if (typ==1)
    			a[++tot].x=rd(),a[tot].y=rd(),a[tot].pos=rd(),cr[++k]=n;
    		else ++tot,a[tot]=(node){++m,rd(),rd(),rd(),0},ty[tot]=1;
    	}
    	cr[k+1]=n,k=0;
    	q=tot;
    	for (int i=2;i<=cr[1];++i) link(id[i],id[1]);
    	for (int i=1,lst=1,cur=cr[1]+1;i<=tot;++i)
    		if (!ty[i]){
    			int l=max(a[i].x,lb[a[i].pos]),r=min(a[i].y,rb[a[i].pos]);
    			node x=(node){(l>r)*(m+1),l,++n,lst,a[i].pos};
    			a[i]=x;
    			a[++q]=(node){(l>r)*(m+1),r+1,n,a[i].z,lst};
    			id[n]=++tpp,link(id[n],id[lst]),lst=n;
    			for (++k;cur<=cr[k+1];++cur) link(id[cur],id[n]);
    		}
    	sort(a+1,a+q+1);
    	tot=0;
    	for (int i=1;i<=q;++i)
    		if (!a[i].id)
    			cut(id[a[i].x],id[a[i].y]),link(id[a[i].x],id[a[i].z]);
    		else if (a[i].id<=m){
    			access(id[a[i].x]),splay(id[1]),ans[a[i].id]+=id[1]->sum;
    			nd *z=access(id[a[i].y]);splay(id[1]),ans[a[i].id]+=id[1]->sum;
    			access(z),splay(id[1]),ans[a[i].id]-=2*id[1]->sum;
    			if (++tot==m) break;
    		}
    	for (int i=1;i<=m;++i) printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    WPF之触发器
    WP之样式
    SqlServer2012——多表连接查询
    SqlServer2012——Select,分组,排序、插入
    sqlserver——视图
    SqlServer规则
    SqlServer自定义数据类型
    SqlServer2012——表
    ES基础使用
    ELK安装
  • 原文地址:https://www.cnblogs.com/zzqtxdy/p/11488107.html
Copyright © 2020-2023  润新知