QTREE6 - Query on a tree VI

本文介绍了一种使用树剖结合线段树的数据结构来解决特定类型的问题的方法。通过单点修改,可以高效更新节点及其所在联通块的大小,并进行查询操作。文章详细展示了实现过程,包括树剖、线段树维护等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于一个节点,用树剖、线段树维护它为黑/ 白色时它所在联通块大小(仅限于以它为根的子树)。
由于是单点修改,可能受影响的只有其父亲、父亲的父亲、父亲的父亲的父亲、、、
因此把log个区间全部改掉就好了。
但是细节奇多无比。
还有,图中每一种情况都可能碰到根,请自行特判。
对于询问,只需不停跳爸爸,找到联通块内离它最远的颜色相同的祖先,单点查询即可。
昨晚调了半天,上BZOJ一交,发现自己T了。
然后上Vjudge上一交,半天都跑不出来,估计也T了,然后只能去睡觉了QAQ。
然而今早起来一看突然发现A了,删掉O2重交一发,发现跑得更快了?!
反正最后用了210秒死。
蛤蛤蛤蛤蛤蛤蛤蛤蛤蛤蛤蛤
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define G getchar()
#define LL long long
#define pll pair<int,int>
#define mkp make_pair
#define X first
#define Y second
const int N=100005;
int n;bool col[N];
int he[N],ne[N<<1],to[N<<1],tot;
int sz[N],dad[N],son[N],dfn[N],nfd[N],cnt,pre[N];
LL sz0[N<<2],sz1[N<<2],lz0[N<<2],lz1[N<<2];int flg[N<<2];
void read(int &x){
	char ch=getchar();
	while(ch<48||ch>57)ch=G;
	for(x=0;ch>=48&&ch<=57;ch=G)x=x*10+ch-48;
}
void add(int x,int y){
	to[++tot]=y;ne[tot]=he[x];he[x]=tot;
}
void DFS1(int x,int e){
	int y,i;sz[x]=1;
	for(i=he[x];i;i=ne[i])if(i!=e){
		pre[y=to[i]]=x;
		DFS1(y,i^1);
		if(sz[son[x]]<sz[y])son[x]=y;
		sz[x]+=sz[y];
	}
}
void DFS2(int x){
	int i,y;nfd[dfn[x]=++cnt]=x;
	dad[x]=son[pre[x]]==x?dad[pre[x]]:x;
	if(son[x])DFS2(son[x]);
	for(i=he[x];i;i=ne[i])if(!dfn[y=to[i]])
		DFS2(y);
}
void up0(int num){
	sz0[num]=sz0[num<<1]+sz0[num<<1|1];
}
void build0(int l,int r,int num){
	if(l==r){
		sz0[num]=sz[nfd[l]];return;
	}
	int mid=l+r>>1;
	build0(l,mid,num<<1);build0(mid+1,r,num<<1|1);
	up0(num);
}
void up1(int num){
	sz1[num]=sz1[num<<1]+sz1[num<<1|1];
}
void build1(int l,int r,int num){
	if(l==r){
		sz1[num]=1;return;
	}
	int mid=l+r>>1;
	build1(l,mid,num<<1);build1(mid+1,r,num<<1|1);
	up1(num);
}
void pd0(int x,int num){
	if(x>1){
		lz0[num<<1]+=lz0[num];
		lz0[num<<1|1]+=lz0[num];
		sz0[num<<1]+=lz0[num]*(x+1>>1);
		sz0[num<<1|1]+=lz0[num]*(x>>1);
	}
	lz0[num]=0;
}
LL query0(int x,int l,int r,int num){
	if(l==r)return sz0[num];
	int mid=l+r>>1;
	pd0(r-l+1,num);
	if(x<=mid)return query0(x,l,mid,num<<1);
	return query0(x,mid+1,r,num<<1|1);
}
void pd1(int x,int num){
	if(x>1){
		lz1[num<<1]+=lz1[num];
		lz1[num<<1|1]+=lz1[num];
		sz1[num<<1]+=lz1[num]*(x+1>>1);
		sz1[num<<1|1]+=lz1[num]*(x>>1);
	}
	lz1[num]=0;
}
LL query1(int x,int l,int r,int num){
	if(l==r)return sz1[num];
	int mid=l+r>>1;
	pd1(r-l+1,num);
	if(x<=mid)return query1(x,l,mid,num<<1);
	return query1(x,mid+1,r,num<<1|1);
}
void up2(int num){
	flg[num]=flg[num<<1]==flg[num<<1|1]?flg[num<<1]:2;
}
void modify2(int x,int l,int r,int num){
	if(l==r){
		flg[num]=col[nfd[l]];return;
	}
	int mid=l+r>>1;
	if(x<=mid)modify2(x,l,mid,num<<1);
	else modify2(x,mid+1,r,num<<1|1);
	up2(num);
}
int query2(int L,int R,int l,int r,int num){
	if(L<=l&&r<=R)return flg[num];
	int mid=l+r>>1;
	if(R<=mid)return query2(L,R,l,mid,num<<1);
	if(L>mid)return query2(L,R,mid+1,r,num<<1|1);
	int tmp=query2(L,R,l,mid,num<<1);
	return tmp==2||query2(L,R,mid+1,r,num<<1|1)!=tmp?2:tmp;
}
void modify0(int L,int R,LL x,int l,int r,int num){
	if(L<=l&&r<=R){
		lz0[num]+=x;
		sz0[num]+=(r-l+1)*x;
		return;
	}
	pd0(r-l+1,num);
	int mid=l+r>>1;
	if(L<=mid)modify0(L,R,x,l,mid,num<<1);
	if(R>mid)modify0(L,R,x,mid+1,r,num<<1|1);
	up0(num);
}
void modify1(int L,int R,LL x,int l,int r,int num){
	if(L<=l&&r<=R){
		lz1[num]+=x;
		sz1[num]+=(r-l+1)*x;
		return;
	}
	pd1(r-l+1,num);
	int mid=l+r>>1;
	if(L<=mid)modify1(L,R,x,l,mid,num<<1);
	if(R>mid)modify1(L,R,x,mid+1,r,num<<1|1);
	up1(num);
}
int main(){
	int i,Q,x,y,z,o,tmp,l,r,mid;LL gs0,gs1;bool co;
	read(n);tot=1;
	rep(i,2,n){
		read(x);read(y);
		add(x,y);add(y,x);
	}
	DFS1(1,0);DFS2(1);
	build0(1,n,1);build1(1,n,1);
	for(read(Q);Q--;){
		read(o);read(x);
		if(o){
			gs0=query0(dfn[x],1,n,1);gs1=query1(dfn[x],1,n,1);
			z=x;
			if(x>1){
				co=col[x=pre[x]];
				if(col[z]){
					modify0(dfn[x],dfn[x],gs0,1,n,1);
					modify1(dfn[x],dfn[x],-gs1,1,n,1);
					for(x=pre[x];x&&query2(dfn[y=dad[x]],dfn[x],1,n,1)==co;x=pre[y]){
						if(!co)modify0(dfn[y],dfn[x],gs0,1,n,1);
						else modify1(dfn[y],dfn[x],-gs1,1,n,1);
					}
					if(x){
						for(l=dfn[y]+1,r=dfn[x];l<=r;){
							mid=l+r>>1;
							if(query2(mid,dfn[x],1,n,1)==co)
								r=mid-1;
							else l=mid+1;
						}
						if(!co)modify0(r,dfn[x],gs0,1,n,1);
						else modify1(r,dfn[x],-gs1,1,n,1);
					}
				}
				else{
					modify0(dfn[x],dfn[x],-gs0,1,n,1);
					modify1(dfn[x],dfn[x],gs1,1,n,1);
					for(x=pre[x];x&&query2(dfn[y=dad[x]],dfn[x],1,n,1)==co;x=pre[y]){
						if(!co)modify0(dfn[y],dfn[x],-gs0,1,n,1);
						else modify1(dfn[y],dfn[x],gs1,1,n,1);
					}
					if(x){
						for(l=dfn[y]+1,r=dfn[x];l<=r;){
							mid=l+r>>1;
							if(query2(mid,dfn[x],1,n,1)==co)
								r=mid-1;
							else l=mid+1;
						}
						if(!co)modify0(r,dfn[x],-gs0,1,n,1);
						else modify1(r,dfn[x],gs1,1,n,1);
					}
				}
			}
			col[z]^=1;modify2(dfn[z],1,n,1);
		}
		else{
			if(col[x]){
				while(x&&query2(dfn[y=dad[x]],dfn[x],1,n,1)==1)x=pre[z=y];
				if(!x){
					printf("%d\n",query1(1,1,n,1));
					continue;
				}
				for(l=dfn[y]+1,r=dfn[x];l<=r;){
					mid=l+r>>1;
					if(query2(mid,dfn[x],1,n,1)==1)
						r=mid-1;
					else l=mid+1;
				}
				if(l>dfn[x])printf("%d\n",query1(dfn[z],1,n,1));
				else printf("%d\n",query1(l,1,n,1));
			}
			else{
				while(x&&!query2(dfn[y=dad[x]],dfn[x],1,n,1))x=pre[z=y];
				if(!x){
					printf("%d\n",query0(1,1,n,1));
					continue;
				}
				for(l=dfn[y]+1,r=dfn[x];l<=r;){
					mid=l+r>>1;
					if(!query2(mid,dfn[x],1,n,1))
						r=mid-1;
					else l=mid+1;
				}
				if(l>dfn[x])printf("%d\n",query0(dfn[z],1,n,1));
				else printf("%d\n",query0(l,1,n,1));
			}
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值