[LCT 线段树 dfs序] BZOJ 3779 重组病毒

%%%PoPoQQQ http://blog.csdn.net/popoqqq/article/details/45919545

”题目大意:给定一棵树,初始每个点都有一个颜色,支持三种操作: 
1.将某个点到根的路径上所有点染上一种新的颜色 
2.将某个点到根的路径上所有点染上一种新的颜色,然后把根设为这个点 
3.定义一个点的代价为这个点到根路径上颜色的种类数,求某个点子树中所有点代价的平均值

容易发现这玩应就是个LCT,操作1就是Access,操作2就是Move_To_Root,代价就是一个点到根路径上的虚边数量+1

我们用LCT模拟上述操作,用线段树维护DFS序维护信息,一旦LCT中出现了虚实边的切换,就在DFS序上对应的子树+1/-1,查询就直接在线段树上查就行了“


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define V G[p].v
using namespace std;
typedef long long ll;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline void read(char *s)
{
	char c=nc(); int len=0;
	for (;!(c>='A' && c<='Z');c=nc());
	for (len=0;c>='A' && c<='Z';s[++len]=c,c=nc()); s[++len]=0;
}

const int N=100005;

namespace BIT{ 
	#define lowbit(x) ((x)&-(x))
	ll maxn,c1[N],c2[N];  
	inline void init(int n){  
		maxn=n;  
	}  
	inline void add(int x,ll r){  
		for (int i=x;i<=maxn;i+=lowbit(i))  
			c1[i]+=r,c2[i]+=x*r;  
	}  
	inline void add(int l,int r,ll x){
		if (l>r) return;
		add(l,x); add(r+1,-x);  
	}
	inline ll sum(int x){
		ll ret1=0,ret2=0;
		for (int i=x;i;i-=lowbit(i))
			ret1+=c1[i],ret2+=c2[i];
		return (x+1)*ret1-ret2;
	}
	inline ll sum(int l,int r){
		if (l>r) return 0;
		return sum(r)-sum(l-1);
	}
}

struct edge{  
	int u,v,next;  
};  
  
edge G[N*2];  
int head[N],inum;  
  
inline void add(int u,int v,int p)  
{  
	G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;  
}

int n,Q,rt;
int clk,tid[N],last[N];
int fat[N][21],size[N],depth[N];

inline void Modify(int x,int val);

struct Splay{  
	struct node{  
		node *p,*ch[2],*fat;  
		int size,rev,idx; 
		bool dir() { return this==p->ch[1]; }  
		void setc(node *c,int d) { ch[d]=c; c->p=this; }  
		void update(){  
			size=ch[0]->size+ch[1]->size+1;
		}   
		void reverse(){  
			rev^=1;   swap(ch[0],ch[1]);
		}
		void pushdown(node *null)  {  
			if (rev)   
			{  
				if (ch[0]!=null) ch[0]->reverse();  
				if (ch[1]!=null) ch[1]->reverse();  
				rev=0;  
			}
		}  
	}*null;  
	node Mem[N];  
	Splay(){  
		null=Mem; null->p=null->ch[0]=null->ch[1]=null; null->size=0;  
	}  
	void rot(node *x){  
		if (x==null) return;  
		bool d=x->dir(); node *p=x->p;  
		if (p->p!=null) p->p->setc(x,p->dir()); else x->p=null;  
		p->setc(x->ch[d^1],d); x->setc(p,d^1); p->update(); x->update(); swap(x->fat,p->fat);  
	}  
	node *stk[N];int pnt;  
	void splay(node *x){  
		node *y=x; pnt=0;  
		while (y!=null) stk[++pnt]=y,y=y->p;  
		for (int i=pnt;i;i--)   
			stk[i]->pushdown(null);  
		while (x->p!=null)  
			if (x->p->p==null)  
				rot(x);  
			else   
				(x->dir()==x->p->dir())?(rot(x->p),rot(x)):(rot(x),rot(x));  
	}
	void Solve(node *x,int val)
	{
		if (x==null) return; 
		x->pushdown(null);
		while (x->ch[0]!=null) x=x->ch[0],x->pushdown(null);
		Modify(x->idx,val);
	}
	node *Access(node *x){  
		node *y=null;  
		while (x!=null)  
		{  
			splay(x);  
			x->ch[1]->p=null; x->ch[1]->fat=x;;
			Solve(x->ch[1],1);
			x->setc(y,1); y->fat=null;  
			Solve(y,-1);
			x->update();  
			y=x; x=x->fat;  
		}  
		return y;  
	}
}LCT;
  
Splay::node *pos[N];  

inline void Init(int n){
	for (int i=1;i<=n;i++)  
	{  
		pos[i]=LCT.Mem+i; pos[i]->size=1; pos[i]->idx=i;
		pos[i]->p=pos[i]->ch[0]=pos[i]->ch[1]=pos[i]->fat=LCT.null;  
	}  
}

inline int dfs(int u,int fa)  
{  
	tid[u]=++clk; size[u]=1; depth[u]=depth[fa]+1; fat[u][0]=fa;
	for (int k=1;k<=20;k++) fat[u][k]=fat[fat[u][k-1]][k-1];
	BIT::add(tid[u],tid[u],depth[u]);
	if (!fa) pos[u]->fat=LCT.null; else pos[u]->fat=pos[fa];
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
			size[u]+=dfs(V,u);
	last[u]=tid[u]+size[u]-1;
	return size[u];
}

inline int LCA(int u,int v){  
    if (depth[u]<depth[v]) swap(u,v);  
    for (int k=20;~k;k--)  
        if ((depth[u]-depth[v])&(1<<k))  
            u=fat[u][k];  
    if (u==v) return v;  
    for (int k=20;~k;k--)  
        if (fat[u][k]!=fat[v][k])  
            u=fat[u][k],v=fat[v][k];  
    return fat[u][0];
}

inline int Fat(int x,int y){
	for (int k=20;~k;k--)
		if (depth[fat[x][k]]>depth[y])
			x=fat[x][k];
	return x;
}

inline void Modify(int x,int val)
{
    if(x==rt)
    {
        BIT::add(1,n,val);
        return ;
    }
    int lca=LCA(x,rt);
    if(lca!=x)
        BIT::add(tid[x],last[x],val);
    else
    {
    	int y=Fat(rt,x);
		BIT::add(1,tid[y]-1,val);
        BIT::add(last[y]+1,n,val);
    }
}

inline ll Sum(int x)
{
	if(x==rt)
        return BIT::sum(1,n);
    int lca=LCA(x,rt);
    if(lca!=x)
        return BIT::sum(tid[x],last[x]);
    else
    {
    	int y=Fat(rt,x);
		return BIT::sum(1,tid[y]-1)+BIT::sum(last[y]+1,n);
    }
}

inline ll Size(int x)
{
	if(x==rt)
        return n;
    int lca=LCA(x,rt);
    if(lca!=x)
        return size[x];
    else
    {
    	int y=Fat(rt,x);
		return n-size[y];
    }
}

int main()
{
	int iu,iv,x; char order[10]; ll ret,tot;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(n); read(Q); Init(n); BIT::init(n);
	for (int i=1;i<n;i++) read(iu),read(iv),add(iu,iv,++inum),add(iv,iu,++inum);
	dfs(1,0); rt=1;
//	for (int i=1;i<=n;i++) printf("%lld ",BIT::sum(i,i)); printf("\n");
	while (Q--)
	{
		read(order); read(x);
		if (!strcmp(order+1,"RELEASE")){
			LCT.Access(pos[x]);
		}
		else if (!strcmp(order+1,"RECENTER")){
			LCT.Access(pos[x])->reverse(); rt=x;
		}
		else if (!strcmp(order+1,"REQUEST")){
			ret=Sum(x);
			tot=Size(x);
			printf("%.10lf\n",(double)ret/tot);
		}
//		for (int i=1;i<=n;i++) printf("%lld ",BIT::sum(i,i)); printf("\n");
	}
	return 0;
}


你可能感兴趣的:([LCT 线段树 dfs序] BZOJ 3779 重组病毒)