bzoj 3553: [Shoi2014]三叉神经树

题目大意:给你一棵树,除了叶子结点外每个点的都是三个儿子,每个结点都有一个状态0 or 1,每个非叶子结点的状态是其儿子中较多的那种,叶子结点的状态是给定的,支持修改与查询操作,即改变一个叶子结点的状态,或者查询根结点的状态。 n<=500000 m<=500000


    首先,树链剖分一下(叶子结点不要管),然后对于线段树上维护每个结点的状态(儿子中有几个是1),然后如果是把一个点从0改成1,那么就查询从他父亲到根结点最近的不是(1,0,0)的点x,然后把它到x的全改为(1,1,0),然后查询x->fa的状态,然后修改成多一个1的状态。1改0的话类似。。。   
    查询的话,就是线段树中单点查询了
    线段树中只需要维护右起最长连续的(0,0,1),与右起最长连续的(0,1,1)就ok了
    复杂度的话   修改log^2n,查询logn

#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=500011,maxm=1500011,ncov=-1;
inline void read(int &x){
	x=0; char ch=getchar();
	while (!isdigit(ch)) ch=getchar();
	for (;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
}
inline void read_(int &x){
	char ch=getchar(); while (!isdigit(ch)) ch=getchar(); x=ch-'0';	
}
int map[maxn][3],v[maxm],fa[maxm],n;
void init(){
	read(n);
	for (int i=1;i<=n;++i) for (int j=0;j<3;++j) read(map[i][j]),fa[map[i][j]]=i;
	for (int i=n+1,m=3*n+1;i<=m;++i) read_(v[i]),v[fa[i]]+=v[i];
}
int dep[maxn],top[maxn],sz[maxn],dfn[maxn],seq[maxn];
void getseq(){
	static int q[maxn]; dep[1]=1; fa[1]=0; q[1]=1;
	for (int i=1,w=1;i<=n;++i) for (int j=0;j<3;++j) if (map[q[i]][j]<=n)
		q[++w]=map[q[i]][j],dep[q[w]]=dep[q[i]]+1;
	for (int i=1;i<=n;++i) top[i]=i,sz[i]=1;
	for (int i=n;i>=1;--i) sz[fa[q[i]]]+=sz[q[i]]; sz[0]=0; dfn[1]=1;
	for (int i=1;i<=n;++i){
		int x=q[i],res=dfn[x],tmp=0;
		for (int j=0;j<3;++j) if (map[x][j]<=n && sz[map[x][j]]>sz[tmp]) tmp=map[x][j];
		if (tmp){dfn[tmp]=res+1; res+=sz[tmp]; top[tmp]=top[x];}
		for (int j=0;j<3;++j) if (map[x][j]<=n && map[x][j]!=tmp)
			dfn[map[x][j]]=res+1,res+=sz[map[x][j]];
	}
	
	for (int i=1;i<=n;++i)
		assert(dfn[i]>=0 && dfn[i]<=n && dep[i]>0 && sz[i]>0 && top[i]>0 && sz[i]<=n && top[i]<=n);
		
	for (int i=n;i>=1;--i) if (v[q[i]]>=2) ++v[fa[q[i]]];
	for (int i=1;i<=n;++i) seq[dfn[i]]=i;
}
struct Tseg{
	struct node{
		int mx[2],c,sz; // mx[0]代表(0,0,1)的右起连续最长,mx[1]代表(0,1,1)的
		void cov(int c_){
			c=c_; mx[0]=mx[1]=0; if (c==1) mx[0]=sz; if (c==2) mx[1]=sz;
		}
	}t[maxn<<3];
	void update(node &p,node ls,node rs){
		p.sz=ls.sz+rs.sz; p.mx[0]=rs.mx[0]; p.mx[1]=rs.mx[1];
		if (rs.mx[0]==rs.sz) p.mx[0]+=ls.mx[0];
		if (rs.mx[1]==rs.sz) p.mx[1]+=ls.mx[1];
	}
	void pushdown(int p){
		if (t[p].c==ncov) return;
		t[p<<1].cov(t[p].c); t[p<<1|1].cov(t[p].c); t[p].c=ncov;
	}
	void build(int p,int l,int r){
		t[p].c=ncov; if (l==r){t[p].sz=1; t[p].cov(v[seq[l]]); return;}
		int mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r);
		update(t[p],t[p<<1],t[p<<1|1]);
	}
	void clear(){build(1,1,n);}
	int Query(int p,int l,int r,int m){
		if (l==r){assert(l==m); return t[p].c;}
		pushdown(p); int mid=(l+r)>>1;
		if (m<=mid) return Query(p<<1,l,mid,m);
		return Query(p<<1|1,mid+1,r,m);
	}
	node Query(int p,int l,int r,int fir,int las){
		if (l==fir && r==las) return t[p];
		pushdown(p); int mid=(l+r)>>1;
		if (las<=mid) return Query(p<<1,l,mid,fir,las);
		if (fir>mid) return Query(p<<1|1,mid+1,r,fir,las);
		node res; update(res,Query(p<<1,l,mid,fir,mid),Query(p<<1|1,mid+1,r,mid+1,las));
		return res;
	}
	void modify(int p,int l,int r,int fir,int las,int c){
		if (l==fir && r==las) {t[p].cov(c); return;}
		pushdown(p); int mid=(l+r)>>1;
		if (las<=mid) modify(p<<1,l,mid,fir,las,c);
		else if (fir>mid) modify(p<<1|1,mid+1,r,fir,las,c);
		else modify(p<<1,l,mid,fir,mid,c),modify(p<<1|1,mid+1,r,mid+1,las,c);
		update(t[p],t[p<<1],t[p<<1|1]);
	}
	void modify(int x,int p,int c){
		for (;top[x]!=top[p];x=fa[top[x]]) modify(1,1,n,dfn[top[x]],dfn[x],c);
		modify(1,1,n,dfn[p],dfn[x],c);
	}
	int modify(int x){
		int key=v[x]; v[x]=1-v[x];
		// 把key变成1-key
		int tmp=fa[x];
		while (1){
			node res=Query(1,1,n,dfn[top[tmp]],dfn[tmp]);
			if (res.sz!=res.mx[key]) break; tmp=top[tmp];
			if (!fa[tmp]) break;
			if (Query(1,1,n,dfn[fa[tmp]])!=key+1) break; tmp=fa[tmp];
		}
		int p;
		if (Query(1,1,n,dfn[tmp])!=key+1){
			modify(1,1,n,dfn[tmp],dfn[tmp],Query(1,1,n,dfn[tmp])+(key?-1:1));
			return Query(1,1,n,1)>=2;
		}
		if (tmp==top[tmp]) p=tmp;
		else p=seq[dfn[tmp]-Query(1,1,n,dfn[top[tmp]],dfn[tmp]).mx[key]+1];
		modify(fa[x],p,v[x]+1);
		if (fa[p]) modify(1,1,n,dfn[fa[p]],dfn[fa[p]],Query(1,1,n,dfn[fa[p]])+(key?-1:1));
		return Query(1,1,n,1)>=2;
	}
}seg;
void work(){
	getseq(); seg.clear(); int q,a;
	for (read(q);q;--q) read(a),printf("%d\n",seg.modify(a));
}
int main(){
	init();
	work();
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值