• 万家灯火


    ### Description

      给你一棵(n)个点的树,每个点初始的时候有一个为(1)(0)的权值,现在要支持两种操作:

    (op(1,x)):令(x)点的权值反转

    (op(2,x,d)):求距离(x)(leq d)的点中,权值为(1)的点组成的连通块个数(注意(x)点本身不算在内,也就是询问(x)的时候要假装(x)(0)

      数据范围:(1leq n,mleq 10^5)

      

    Solution

      智力康复qwq码+调试搞了差不多一万年也是服了qwq

      操作看过去浓浓的动态点分气息,然后连通块计数直接转成范围内权值为(1)的点的数量(-)满足两个端点的权值都是(1)的边数即可

      所以每个分治中心上我们要维护的东西就是:权值为(1)的点的数量,两个端点权值都是(1)的边的数量

    ​  实现上的话就是树状数组搞一搞就好了

      然后关于修改操作:注意到一个点修改了之后,它连出去的边都会被影响到,然而如果修改的复杂度跟点的度数挂钩随便一个菊花图就凉了,所以考虑换一种方式统计

    ​  我们把边的贡献挂在原树的父亲那里,然后对于每个点维护一下原树儿子中有多少个权值为(1)的即可

      查询的时候注意(d)(-1),然后还有各种奇奇怪怪的边界的细节== 然后我个蒟蒻就写得极其丑陋了qwq

      

      mark:连通块还是直接点数-边数计算比较好。。把贡献挂在“最上面那个点”上。。很明显有很多不优秀的地方。。

      

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=1e5+10,TOP=20,BIT=N*17*2;
    struct xxx{
    	int y,nxt;
    }a[N*2];
    char s[N];
    int h[N],st[N],cnt[N];
    int n,m,tot,q;
    namespace Bit{/*{{{*/
    	int c[BIT][2],st[N][2],mx[N][2];
    	int tot=0;
    	//start from 0, +1
    	void modify(int which,int x,int delta,int op,int tp){//tp=0: -  tp=1: +
    		++x;
    		for (;x<=mx[which][op];x+=x&-x)
    			c[st[which][op]+x][tp]+=delta;
    	}
    	int query(int which,int op,int x,int tp){
    		++x;
    		int ret=0;
    		x=min(x,mx[which][op]);
    		for (;x;x-=x&-x) ret+=c[st[which][op]+x][tp];
    		return ret;
    	}
    }/*}}}*/
    void add(int x,int y){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot;}
    namespace OriT{/*{{{*/
    	int lis[N],dfn[N];
    	int dep[N],top[N],pre[N],son[N],sz[N];
    	int dfn_t;
    	void predfs(int fa,int x,int d){
    		int u;
    		dep[x]=d; ::cnt[x]=0; pre[x]=fa;
    		son[x]=0; sz[x]=1;
    		for (int i=h[x];i!=-1;i=a[i].nxt){
    			u=a[i].y;
    			if (u==fa) continue;
    			predfs(x,u,d+1);
    			::cnt[x]+=st[u];
    			sz[x]+=sz[u];
    			if (sz[u]>sz[son[x]]) son[x]=u;
    		}
    	}
    	void dfs1(int fa,int x){
    		lis[++dfn_t]=x; dfn[x]=dfn_t;
    		if (son[x]){
    			top[son[x]]=top[x];
    			dfs1(x,son[x]);
    		}
    		int u;
    		for (int i=h[x];i!=-1;i=a[i].nxt){
    			u=a[i].y;
    			if (u==fa||u==son[x]) continue;
    			top[u]=u;
    			dfs1(x,u);
    		}
    	}
    	void prework(){
    		predfs(0,1,1);
    		top[1]=1; dfn_t=0;
    		dfs1(0,1);
    	}
    	int get_lca(int x,int y){
    		while (top[x]!=top[y]){
    			if (dep[top[x]]<dep[top[y]]) swap(x,y);
    			x=pre[top[x]];
    		}
    		return dep[x]<dep[y]?x:y;
    	}
    	int get_dis(int x,int y){
    		int lca=get_lca(x,y);
    		return dep[x]+dep[y]-2*dep[lca];
    	}
    	int jump(int x,int d){
    		int aim=dep[x]-d;
    		if (!d) return x;
    		while (dep[top[x]]>aim) x=pre[top[x]];
    		return lis[dfn[x]-(dep[x]-aim)];
    	}
    }/*}}}*/
    namespace T{/*{{{*/
    	int pre[N],sz[N],mx[N];
    	int df_t[N];
    	int vis[N];
    	int cnt0[N],cnt1[N];//0=- 1=+
    	int rec[TOP+1][N][2];
    	int rt,rt_mx,mxdep;
    	void get_sz(int fa,int x){
    		int u;
    		sz[x]=1; mx[x]=0;
    		for (int i=h[x];i!=-1;i=a[i].nxt){
    			u=a[i].y;
    			if (u==fa||vis[u]) continue;
    			get_sz(x,u);
    			sz[x]+=sz[u];
    			mx[x]=max(mx[x],sz[u]);
    		}
    	}
    	void get_rt(int Rt,int fa,int x){
    		int u;
    		mx[x]=max(mx[x],sz[Rt]-sz[x]);
    		if (mx[x]<rt_mx)
    			rt=x,rt_mx=mx[x];
    		for (int i=h[x];i!=-1;i=a[i].nxt){
    			u=a[i].y;
    			if (u==fa||vis[u]) continue;
    			get_rt(Rt,x,u);
    		}
    	}
    	void dfs(int rt_t,int fa,int x,int d,int op){
    		int u;  
    		mxdep=max(mxdep,d);
    		cnt0[d]+=::st[x]?::cnt[x]:0;
    		cnt1[d]+=::st[x];
    		rec[rt_t][x][op]=d;
    		for (int i=h[x];i!=-1;i=a[i].nxt){
    			u=a[i].y;
    			if (u==fa||vis[u]) continue;
    			dfs(rt_t,x,u,d+1,op);
    		}
    	}
    	void get_lis(int x,int rt,int which_t,int op){
    		mxdep=0;
    		Bit::st[rt][op]=Bit::tot;
    		if (op==0)
    			dfs(which_t,0,rt,0,op);
    		else 
    			dfs(which_t,0,x,0,op);
    		Bit::mx[rt][op]=mxdep+1;
    		Bit::tot+=Bit::mx[rt][op];
    
    		for (int i=0;i<=mxdep;++i){
    			Bit::modify(rt,i,cnt0[i],op,0);
    			Bit::modify(rt,i,cnt1[i],op,1);
    			cnt0[i]=0; cnt1[i]=0;
    		}
    	}
    	void solve(int fa,int x){
    		int u,Rt;
    		rt=0,rt_mx=n;
    		get_sz(0,x);
    		get_rt(x,0,x);
    		Rt=rt;
    
    		df_t[Rt]=df_t[fa]+1;
    		pre[Rt]=fa;
    		get_lis(x,Rt,df_t[Rt],0);
    		get_lis(x,Rt,df_t[Rt],1);
    		vis[Rt]=1;
    		for (int i=h[Rt];i!=-1;i=a[i].nxt){
    			u=a[i].y;
    			if (vis[u]) continue;
    			solve(Rt,u);
    		}
    	}
    	int query(int x,int aim,int d,int tp){//tp=0: -  tp=1: +
    		int dis=d-OriT::get_dis(x,aim),pos;
    		int ret=dis>=0?Bit::query(x,0,dis,tp):0;
    		if (pre[x]){
    			dis=d-OriT::get_dis(pre[x],aim)-1;
    			if (dis>=0){
    				ret-=Bit::query(x,1,dis,tp);
    			}
    			ret+=query(pre[x],aim,d,tp);
    		}
    		return ret;
    	}
    	void modify(int x,int aim,int delta,int tp){//tp=0: -  tp=1:+
    		if (!delta) return;
    		Bit::modify(x,rec[df_t[x]][aim][0],delta,0,tp);
    		if (pre[x]){
    			Bit::modify(x,rec[df_t[x]][aim][1],delta,1,tp);
    			modify(pre[x],aim,delta,tp);
    		}
    	}
    }/*}}}*/
    void modify(int x){
    	int delta=st[x]?-1:1;
    	int fa=OriT::pre[x];
    	if (fa&&st[fa])
    		T::modify(fa,fa,delta,0);
    	if (fa) cnt[fa]+=delta;
    	T::modify(x,x,cnt[x]*delta,0);
    	T::modify(x,x,delta,1);
    	st[x]+=delta;
    }
    int query(int x,int d){
    	int tmp1,tmp2,fa=OriT::pre[x];
    	tmp1=T::query(x,x,d-1,0);
    	tmp2=T::query(x,x,d,1);
    	if (st[x]){
    		--tmp2;
    		tmp1-=cnt[x]+st[fa];
    	}
    	if (OriT::dep[x]>d){
    		x=OriT::jump(x,d-1);
    		fa=OriT::pre[x];
    		tmp1+=st[x]&st[fa];
    	}
    	return tmp2-tmp1;
    }
    void prework(){
    	OriT::prework();
    	T::solve(0,1);
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    #endif
    	int x,y,op,d;
    	scanf("%d%d",&n,&m);
    	memset(h,-1,sizeof(h));
    	tot=0;
    	for (int i=1;i<n;++i){
    		scanf("%d%d",&x,&y);
    		add(x,y); add(y,x);
    	}
    	scanf("%s",s+1);
    	for (int i=1;i<=n;++i) st[i]=s[i]=='1';
    	prework();
    	for (int i=1;i<=m;++i){
    		scanf("%d",&op);
    		if (op==1){
    			scanf("%d",&x);
    			modify(x);
    		}
    		else{
    			scanf("%d%d",&x,&d);
    			printf("%d
    ",query(x,d));
    		}
    	}
    }
    /*
    6 3
    1 2
    1 3
    1 4
    2 5
    3 6
    111000
    2 1 2
    2 4 2
    1 1
    2 4 2
    */
    
  • 相关阅读:
    TIME_WAIT和CLOSE_WAIT的区别
    shell备份脚本
    No package 'eventlog' found
    Linux下升级安装Python-3.6.2版本
    mysql的binlog安全删除的一种方法
    windows 清理 cbs.log 文件
    Linux crontab 查看所有用户的crontab任务
    java抽象类与接口回顾
    java类的回顾
    windows的MySQL安装
  • 原文地址:https://www.cnblogs.com/yoyoball/p/10269320.html
Copyright © 2020-2023  润新知