bzoj3731: Gty的超级妹子树

Posted wangyurzee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3731: Gty的超级妹子树相关的知识,希望对你有一定的参考价值。

一代神题啊orz(至少是以前年代的神题吧)

块状树

复杂度nsqrtnlogn

真是exciting

还没有卡时限

话不多说直接上代码

(最近解锁了记事本写代码的技能...感觉越来越依赖OJ调试了...啊感觉写代码准确率高了不少qwq)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <vector>
#define N 200006
#define M 400006

using namespace std;
inline int read(){
	int ret=0;char ch=getchar();
	while (ch<‘0‘||ch>‘9‘) ch=getchar();
	while (‘0‘<=ch&&ch<=‘9‘){
		ret=ret*10-48+ch;
		ch=getchar();
	}
	return ret;
}

const int KK=400;
vector<int> seq[N];

struct edge{
	int adj,next;
	edge(){}
	edge(int _adj,int _next):adj(_adj),next(_next){}
} e[M];
int n,g[N],m;
void AddEdge(int u,int v){
	e[++m]=edge(v,g[u]);g[u]=m;
	e[++m]=edge(u,g[v]);g[v]=m;
}
int w[N];

vector<int> nxt[N];
int fa[N],bl[N],sz[N],cnt,top[N];
void refresh(int u,int p){
	for (;p>0&&seq[u][p]<seq[u][p-1];--p)swap(seq[u][p],seq[u][p-1]);
	for (;p<sz[u]-1&&seq[u][p]>seq[u][p+1];++p)swap(seq[u][p],seq[u][p+1]);
}
void newnode(int u){
	if (sz[bl[fa[u]]]==KK){
		sz[bl[u]=++cnt]=0;
		top[cnt]=u;
	}
	else bl[u]=bl[fa[u]];
	++sz[bl[u]];
}
void dfs(int u){
	newnode(u);
	for (int i=g[u];i;i=e[i].next){
		int v=e[i].adj;
		if (v==fa[u]) continue;
		fa[v]=u;
		dfs(v);
	}
}
void dfs_pre(int u){
	seq[bl[u]].push_back(w[u]);++sz[bl[u]];
	for (int i=g[u];i;i=e[i].next)if (fa[e[i].adj]==u){
		int v=e[i].adj;
		if (bl[v]==bl[u]) dfs_pre(v);
		else nxt[bl[u]].push_back(bl[v]);
	}
}
void prepare(int id){
	seq[id].clear();vector<int>(seq[id]).swap(seq[id]);
	nxt[id].clear();vector<int>(nxt[id]).swap(nxt[id]);
	sz[id]=0;
	dfs_pre(top[id]);
	sort(seq[id].begin(),seq[id].end());
}

int solve(int u,int lmt){
	int l=-1,r=sz[u],mid;
	while (l+1<r){
		mid=l+r>>1;
		if (seq[u][mid]<=lmt) l=mid;
		else r=mid;
	}
	int ret=sz[u]-l-1;
	for (int j=nxt[u].size()-1;j>=0;--j) ret+=solve(nxt[u][j],lmt);
	return ret;
}
int query(int u,int lmt){
	if (bl[u]!=bl[fa[u]]) return solve(bl[u],lmt);
	int ret=w[u]>lmt;
	for (int i=g[u];i;i=e[i].next)if (fa[e[i].adj]==u)ret+=query(e[i].adj,lmt);
	return ret;
}

void modify(int u,int x){
	int p;
	for (int i=0;i<sz[bl[u]];++i)
		if (seq[bl[u]][i]==w[u]){p=i;break;}
	w[u]=x;seq[bl[u]][p]=x;
	refresh(bl[u],p);
}

void create(int u,int x){
	AddEdge(u,++n);fa[n]=u;w[n]=x;
	int tmp=cnt;
	newnode(n);
	seq[bl[n]].push_back(w[n]);
	refresh(bl[n],sz[bl[n]]-1);
	if (tmp<cnt) nxt[bl[u]].push_back(cnt);
}

void dfs_update(int u,int last,int now){
	bl[u]=now;
	for (int i=g[u];i;i=e[i].next)if (fa[e[i].adj]==u)
		if (bl[e[i].adj]==last) dfs_update(e[i].adj,last,now);
}

void cut(int u){
	int lst=bl[u];
	if (bl[fa[u]]!=bl[u]){
		int f=bl[fa[u]];
		for (vector<int>::iterator it=nxt[f].begin();it!=nxt[f].end();++it)
			if ((*it)==lst){nxt[f].erase(it);break;}
		fa[u]=0;return;
	}
	top[++cnt]=u;
	fa[u]=0;
	dfs_update(u,lst,cnt);
	prepare(lst);
	prepare(cnt);
}

int main(){
	n=read();
	memset(g,0,sizeof(g));m=1;
	for (int i=1;i<n;++i) AddEdge(read(),read());
	for (int i=1;i<=n;++i) w[i]=read();
	fa[1]=0;bl[0]=0;sz[0]=KK;cnt=0;
	dfs(1);
	int lastans=0;
	for (int i=1;i<=cnt;++i) prepare(i);
	for (int Q=read();Q;Q--){
		int op=read(),u=read()^lastans,x;
		if (op<3) x=read()^lastans;
		else cut(u);
		if (op==0) printf("%d\n",lastans=query(u,x));
		else if (op==1) modify(u,x);
		else if (op==2) create(u,x);
	}
	return 0;
}

  

以上是关于bzoj3731: Gty的超级妹子树的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3720Gty的妹子树 块状树

BZOJ3720 Gty的妹子树 树分块

bzoj3720 Gty的妹子树

bzoj 3720 Gty的妹子树

bzoj 3720: Gty的妹子树

BZOJ 3720: Gty的妹子树