zoukankan      html  css  js  c++  java
  • 6869. 【2020.11.17提高组模拟】鼠树

    一棵树,点有黑白。称某个点被最近的黑点祖先所“管辖”。管辖其它点的点称为“管辖点”。

    支持如下操作:

    1. 询问(x)的权值。
    2. (x)所管辖的点加权值。
    3. 询问(x)的子树的权值和。
    4. (x)的子树中所有的管辖点做操作。
    5. (x)变黑。
    6. (x)变白。

    (nle 3*10^5,Qle 5*10^5)


    比赛时为什么没有搞出来……

    为了方便记(x)的管辖点为(y)

    由于修改操作太麻烦,不妨考虑操作2只在(y)处加权值,操作1找(y)的权值,操作3求(x)子树中的管辖点的权值和乘管辖范围,另外加上(y)的权值乘(x)子树中包含(x)的白色联通块的大小,操作4区间改管辖点的权值。这样在没有5和6操作时可以随便做。

    现在支持5和6操作。5操作时,找出(y)的权值,插入新点,并将新点的权值设为(y)的权值;6操作时,删除之后,给(x)的子树整体加(w_x-w_y),再用4操作给(x)中所有管辖点权值加(-(w_x-w_y))(w)为权值。

    操作的时候有些小操作,这里就不说了。

    具体的实现的时候,搞三个数据结构:

    1. 用树剖+set,可以做到(O(lg n))地找到每个点对应的管辖点。
    2. 用树状数组,维护给子树整体加的操作。
    3. 用线段树,维护形如(sum c_iw_i)的序列,支持查区间查(sum c_iw_i),区间查(sum c_i),单点查(w_i),单点改(c_i),区间改(w_i)(只改(c_i>0)的部分)。不知道树状数组行不行呢。

    时间复杂度(O(nlg n))


    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #define N 300005
    #define ui unsigned
    #define INF 1000000000
    int n,m;
    int fa[N];
    struct EDGE{
    	int to;
    	EDGE *las;
    } e[N];
    int ne;
    EDGE *last[N];
    
    int dep[N],siz[N],hs[N],top[N],in[N],out[N],nowdfn;
    int mn[N];
    struct cmp{bool operator()(int a,int b){return dep[a]<dep[b];}};
    set<int,cmp> b[N];
    void updmn(int x){
    	mn[x]=(b[x].empty()?INF:dep[*b[x].begin()]);
    }
    void init1(int x){
    	in[x]=++nowdfn;
    	siz[x]=1;
    	for (EDGE *ei=last[x];ei;ei=ei->las){
    		dep[ei->to]=dep[x]+1;
    		init1(ei->to);
    		siz[x]+=siz[ei->to];
    		if (siz[ei->to]>siz[hs[x]])
    			hs[x]=ei->to;
    	}
    	out[x]=nowdfn;
    }
    void init2(int x,int t){
    	top[x]=t;
    	if (hs[x]){
    		init2(hs[x],t);
    		for (EDGE *ei=last[x];ei;ei=ei->las)
    			if (ei->to!=hs[x])
    				init2(ei->to,ei->to);
    	}
    }
    int find(int x){
    	for (;x;x=fa[top[x]])
    		if (mn[top[x]]<=dep[x]){
    			auto p=b[top[x]].upper_bound(x);
    			--p;
    			return *p;
    		}
    }
    
    struct TA{
    	ui t[N];
    	void add(int x,ui c){
    		for (;x<=n;x+=x&-x)
    			t[x]+=c;
    	}
    	ui query(int x){
    		ui r=0;
    		for (;x;x-=x&-x)
    			r+=t[x];
    		return r;
    	}
    };
    struct TA2{
    	TA t0,t1;
    	void add(int l,int r,ui c){
    		t1.add(l,c),t1.add(r+1,-c);
    		t0.add(l,-c*(l-1)),t0.add(r+1,c*r);
    	}
    	ui query(int l,int r){
    		ui s=0;
    		s+=t0.query(r)+t1.query(r)*(ui)r;
    		s-=t0.query(l-1)+t1.query(l-1)*(ui)(l-1);
    		return s;
    	}
    } s;
    
    ui c[N*4],w[N*4],cw[N*4];
    void gt(int k,ui v){
    	if (c[k]){
    		cw[k]+=c[k]*v;
    		w[k]+=v;
    	}
    }
    void upd(int k){
    	c[k]=c[k<<1]+c[k<<1|1];
    	cw[k]=cw[k<<1]+cw[k<<1|1];
    }
    void pd(int k){
    	gt(k<<1,w[k]);
    	gt(k<<1|1,w[k]);
    	w[k]=0;
    }
    ui sum(ui q[],int st,int en,int k=1,int l=1,int r=n){
    	if (st<=l && r<=en)
    		return q[k];
    	pd(k);
    	ui res=0;
    	int mid=l+r>>1;
    	if (st<=mid) res+=sum(q,st,en,k<<1,l,mid);
    	if (mid<en) res+=sum(q,st,en,k<<1|1,mid+1,r);
    	return res;
    }
    void addc(int x,ui v,int k=1,int l=1,int r=n){
    	if (l==r){
    		c[k]+=v;
    		if (!c[k]) w[k]=0;
    		cw[k]=c[k]*w[k];
    		return;
    	}
    	pd(k);
    	int mid=l+r>>1;
    	if (x<=mid) addc(x,v,k<<1,l,mid);
    	else addc(x,v,k<<1|1,mid+1,r);
    	upd(k);
    }
    void addw(int st,int en,ui v,int k=1,int l=1,int r=n){
    	if (st<=l && r<=en){
    		gt(k,v);
    		return;
    	}
    	pd(k);
    	int mid=l+r>>1;
    	if (st<=mid) addw(st,en,v,k<<1,l,mid);
    	if (mid<en) addw(st,en,v,k<<1|1,mid+1,r);
    	upd(k);
    }
    ui qw(int x){return sum(w,in[x],in[x]);}
    ui qc(int x){return sum(c,in[x],in[x]);}
    int main(){
    //	freopen("in.txt","r",stdin);
    //	freopen("out.txt","w",stdout);
    	freopen("pastel.in","r",stdin);
    	freopen("pastel.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for (int i=2;i<=n;++i){
    		scanf("%d",&fa[i]);
    		e[ne]={i,last[fa[i]]};
    		last[fa[i]]=e+ne++;
    	}
    	init1(1);
    	init2(1,1);
    	for (int i=1;i<=n;++i)
    		mn[i]=INF;
    	b[1].insert(1);
    	updmn(1);
    	addc(in[1],siz[1]);
    	while (m--){
    		int op,x;
    		scanf("%d%d",&op,&x);
    		if (op==1){
    			int y=find(x);
    			printf("%u
    ",qw(y)+s.query(in[x],in[x]));
    		}
    		else if (op==3){
    			int y=find(x);
    			ui ans=sum(cw,in[x],out[x])+(siz[x]-sum(c,in[x],out[x]))*qw(y);
    			ans+=s.query(in[x],out[x]);
    			printf("%u
    ",ans);
    		}
    		else if (op==5){
    			int y=find(x);
    			ui w=qw(y),v=siz[x]-sum(c,in[x],out[x]);
    			addc(in[y],-v);
    			addc(in[x],v),addw(in[x],in[x],w);
    			b[top[x]].insert(x);
    			updmn(top[x]);
    		}
    		else if (op==6){
    			int y=find(fa[x]);
    			ui w=qw(x),v=qc(x);
    			addc(in[y],+v);
    			addc(in[x],-v);
    //			addw(in[x],in[x],-w);	
    			w=w-qw(y);
    			s.add(in[x],out[x],w);
    			addw(in[x],out[x],-w);
    			b[top[x]].erase(x);
    			updmn(top[x]);
    		}
    		else{
    			ui v;
    			scanf("%u",&v);
    			if (op==2)
    				addw(in[x],in[x],v);
    			else
    				addw(in[x],out[x],v);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    centos下卸载rpm包
    centos下添加环境变量和启动apache
    centos(linux) 下如何查看端口占用情况及杀死进程
    如何使上层的div遮住的链接可以点击
    jquery.blockUI.2.31.js 弹出层项目介绍
    fieldset、legend、display html元素
    <a>标签中href="javascript:;"的意思
    memcache 学习笔记
    sublime text3 JS语法检测插件
    Apache Rewrite的主要功能
  • 原文地址:https://www.cnblogs.com/jz-597/p/13995828.html
Copyright © 2011-2022 走看看