[树上莫队] BZOJ 3757 3052 4129

8 篇文章 0 订阅

传送门

http://blog.csdn.net/kuribohG/article/details/41458639

http://vfleaking.blog.163.com/blog/static/174807634201311011201627/

用S(v, u)代表 v到u的路径上的结点的集合。

用root来代表根结点,用lca(v, u)来代表v、u的最近公共祖先。

那么

S(v, u) = S(root, v) xor S(root, u) xor lca(v, u)

其中xor是集合的对称差。

简单来说就是节点出现两次消掉。

lca很讨厌,于是再定义

T(v, u) = S(root, v) xor S(root, u)

观察将curV移动到targetV前后T(curV, curU)变化:

T(curV, curU) = S(root, curV) xor S(root, curU)

T(targetV, curU) = S(root, targetV) xor S(root, curU)

取对称差:

T(curV, curU) xor T(targetV, curU)= (S(root, curV) xor S(root, curU)) xor (S(root, targetV) xor S(root, curU))

由于对称差的交换律、结合律:

T(curV, curU) xor T(targetV, curU)= S(root, curV) xorS(root, targetV)

两边同时xor T(curV, curU):

T(targetV, curU)= T(curV, curU) xor S(root, curV) xor S(root, targetV)

发现最后两项很爽……哇哈哈

T(targetV, curU)= T(curV, curU) xor T(curV, targetV)

(有公式恐惧症的不要走啊 T_T)

也就是说,更新的时候,xor T(curV, targetV)就行了。

即,对curV到targetV路径(除开lca(curV, targetV))上的结点,将它们的存在性取反即可。

——vfk博客


BZOJ 3757

裸 树上莫队

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define V G[p].v
using namespace std;

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;
}
 
struct edge{
	int u,v;
	int next;
};

edge G[100005];
int head[50005],inum=1;

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,m,B,rt;
int c[50005];
int clk,pre[50005],depth[50005],parent[50005][20];

inline void dfs(int u,int fa)
{
	pre[u]=++clk;
	depth[u]=depth[fa]+1; parent[u][0]=fa;
	for (int k=1;k<=18;k++)
		parent[u][k]=parent[parent[u][k-1]][k-1];
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
			dfs(V,u);
}

int Stk[50005],top;
int bot,pos[50005];

inline void find(int u,int fa)
{
	int last=top;
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
		{
			find(V,u);
			if (top-last>=B)
			{
				++bot;
				while (top!=last) pos[Stk[top--]]=bot;
			}
		}
	Stk[++top]=u;
}

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

struct que{
	int u,v,a,b;
	int idx;
}Q[100005];

inline bool cmp(que A,que B)
{
	return pos[A.u]==pos[B.u]?pre[A.v]<pre[B.v]:pos[A.u]<pos[B.u];
}

int vst[50005];
int cnt[50005];
int tot;

inline void Rev(int x)
{
	if (!vst[x])
	{
		vst[x]=1,cnt[c[x]]++; if (cnt[c[x]]==1) tot++;
	}
	else
	{
		vst[x]=0,cnt[c[x]]--; if (cnt[c[x]]==0) tot--;
	}
}

inline void T(int u,int v)
{
	while (u!=v)
		if (depth[u]<depth[v])
			Rev(v),v=parent[v][0];
		else
			Rev(u),u=parent[u][0];
}

int ans[100005];

inline void Solve()
{
	int lca;
	T(Q[1].u,Q[1].v);
	lca=LCA(Q[1].u,Q[1].v);
	Rev(lca);
	ans[Q[1].idx]=tot;
	if (Q[1].a!=Q[1].b && cnt[Q[1].a] && cnt[Q[1].b]) ans[Q[1].idx]--;
	Rev(lca);
	for (int i=2;i<=m;i++)
	{
		T(Q[i].u,Q[i-1].u);
		T(Q[i].v,Q[i-1].v);
		lca=LCA(Q[i].u,Q[i].v);
		Rev(lca);
		ans[Q[i].idx]=tot;
		if (Q[i].a!=Q[i].b && cnt[Q[i].a] && cnt[Q[i].b]) ans[Q[i].idx]--;
		Rev(lca);
	}
}

int main()
{
	int _u,_v;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(n); read(m);
	for (int i=1;i<=n;i++)
		read(c[i]);
	for (int i=1;i<=n;i++)
	{
		read(_u),read(_v);
		if (!_u) rt=_v;
		else if (!_v) rt=_u;
		else add(_u,_v,++inum),add(_v,_u,++inum);
	}
	dfs(rt,0);
	B=sqrt(n);
	find(rt,0);
	while (top) pos[Stk[top--]]=bot;
	for (int i=1;i<=m;i++)
	{
		read(Q[i].u); read(Q[i].v); read(Q[i].a); read(Q[i].b); Q[i].idx=i;
		if (pre[Q[i].u]>pre[Q[i].v]) swap(Q[i].u,Q[i].v);
	}
	sort(Q+1,Q+m+1,cmp);
	Solve();
	for (int i=1;i<=m;i++)
		printf("%d\n",ans[i]);
	return 0;
}

BZOJ 3052

带修改 树上莫队

暴力时间前流倒流

分块 N^(2/3)

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#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;
}
 
struct edge{
	int u,v;
	int next;
};

edge G[200005];
int head[100005],inum=1;

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,m,_q,B;
int _V[100005],W[100005],C[100005];
int clk,pre[100005],depth[100005],parent[100005][21];

inline void dfs(int u,int fa)
{
	pre[u]=++clk;
	depth[u]=depth[fa]+1; parent[u][0]=fa;
	for (int k=1;k<=20;k++)
		parent[u][k]=parent[parent[u][k-1]][k-1];
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
			dfs(V,u);
}

int Stk[100005],top;
int bot,pos[100005];

inline void find(int u,int fa)
{
	int last=top;
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
		{
			find(V,u);
			if (top-last>=B)
			{
				++bot;
				while (top!=last) pos[Stk[top--]]=bot;
			}
		}
	Stk[++top]=u;
}

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

struct que{
	int u,v,t;
	int idx;
}Q[100005];
int cnt1;

inline bool cmp(que A,que B)
{
	return pos[A.u]==pos[B.u]?pre[A.v]<pre[B.v]:pos[A.u]<pos[B.u];
}

struct chg{
	int x,y,t;
	int pre;
}X[100005];
int cnt2;
int ihead[100005];

ll ans[100005];
ll ret;

int vst[100005];
int cnt[100005];

inline void Rev(int x)
{
	if (vst[x])
	{
		vst[x]=0; ret-=(ll)W[cnt[C[x]]]*_V[C[x]]; cnt[C[x]]--;
	}
	else 
	{
		vst[x]=1; cnt[C[x]]++; ret+=(ll)W[cnt[C[x]]]*_V[C[x]];
	}
}

inline void T(int u,int v)
{
	while (u!=v)
		if (depth[u]<depth[v])
			Rev(v),v=parent[v][0];
		else
			Rev(u),u=parent[u][0];
}

inline void change(int x,int y)
{
	if (vst[x])
	{
		Rev(x); C[x]=y; Rev(x);
	}
	else 
		C[x]=y;
}

inline void Solve()
{
	int lca;
	for (int i=1;i<=Q[1].t;i++)
		change(X[i].x,X[i].y);
	T(Q[1].u,Q[1].v);
	lca=LCA(Q[1].u,Q[1].v);
	Rev(lca);
	ans[Q[1].idx]=ret;
	Rev(lca);
	for (int i=2;i<=cnt1;i++)
	{
		for (int j=Q[i-1].t+1;j<=Q[i].t;j++)
			change(X[j].x,X[j].y);
		for (int j=Q[i-1].t;j>Q[i].t;j--)
			change(X[j].x,X[j].pre);
		T(Q[i-1].u,Q[i].u);
		T(Q[i-1].v,Q[i].v);
		lca=LCA(Q[i].u,Q[i].v);
		Rev(lca);
		ans[Q[i].idx]=ret;
		Rev(lca);
	} 
}

int main()
{
	int _u,_v,order;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(n); read(m); read(_q);
	for (int i=1;i<=m;i++) read(_V[i]);
	for (int i=1;i<=n;i++) read(W[i]);
	for (int i=1;i<n;i++)
	{
		read(_u); read(_v); 
		add(_u,_v,++inum); add(_v,_u,++inum);
	}
	dfs(1,0);
	B=pow(n,2.0/3);
	find(1,0);
	while (top) pos[Stk[top--]]=bot;
	for (int i=1;i<=n;i++) read(C[i]),ihead[i]=C[i];
	for (int i=1;i<=_q;i++)
	{
		read(order); read(_u); read(_v);
		if (!order)
		{
			X[++cnt2].x=_u; X[cnt2].y=_v; X[cnt2].t=i; X[cnt2].pre=ihead[_u]; ihead[_u]=_v;
		}
		else
		{
			Q[++cnt1].u=_u; Q[cnt1].v=_v; Q[cnt1].t=cnt2; Q[cnt1].idx=cnt1;
			if (pre[Q[cnt1].u]>pre[Q[cnt1].v]) swap(Q[cnt1].u,Q[cnt1].v);
		}
	}
	sort(Q+1,Q+cnt1+1,cmp);
	Solve();
	for (int i=1;i<=cnt1;i++)
		printf("%lld\n",ans[i]);
	return 0;
}

BZOJ 4129

分块查询

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#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;
}
 
struct edge{
	int u,v;
	int next;
};

edge G[100005];
int head[50005],inum=1;

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,m,_q,B;
int C[50005];
int clk,pre[50005],depth[50005],parent[50005][21];

inline void dfs(int u,int fa)
{
	pre[u]=++clk;
	depth[u]=depth[fa]+1; parent[u][0]=fa;
	for (int k=1;k<=20;k++)
		parent[u][k]=parent[parent[u][k-1]][k-1];
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
			dfs(V,u);
}

int Stk[50005],top;
int bot,pos[50005];

inline void find(int u,int fa)
{
	int last=top;
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
		{
			find(V,u);
			if (top-last>=B)
			{
				++bot;
				while (top!=last) pos[Stk[top--]]=bot;
			}
		}
	Stk[++top]=u;
}

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

struct que{
	int u,v,t;
	int idx;
}Q[50005];
int cnt1;

inline bool cmp(que A,que B)
{
	return pos[A.u]==pos[B.u]?pre[A.v]<pre[B.v]:pos[A.u]<pos[B.u];
}

struct chg{
	int x,y,t;
	int pre;
}X[50005];
int cnt2;
int ihead[50005];

namespace Block{
	int pos[50015];
	int cnt[50015];
	int btot,sum[50015],size[50015];
	int n,block;
	inline void init(int _n){
		n=_n+5;
		block=sqrt(n);
		for (int i=1;i<=n;i++)
			pos[i]=(i-1)/block+1,size[pos[i]]++;
		btot=pos[n];
	}
	inline void add(int x,int r)
	{
		x++;
		if (x>n) return;
		if (r==1)
		{
			cnt[x]++;
			if (cnt[x]==1)
				sum[pos[x]]++;
		}
		else
		{
			cnt[x]--;
			if (cnt[x]==0)
				sum[pos[x]]--;
		}
	}
	inline int query()
	{
		for (int i=1;i<=btot;i++)
			if (sum[i]!=size[i])
				for (int j=(i-1)*block+1;;j++)
					if (!cnt[j])
						return j-1;
	}
}

int vst[50005];

inline void Rev(int x)
{
	if (!vst[x])
	{
		vst[x]=1; Block::add(C[x],1);
	}
	else
	{
		vst[x]=0; Block::add(C[x],-1);
	}
}

inline void T(int u,int v)
{
	while (u!=v)
		if (depth[u]>depth[v])
			Rev(u),u=parent[u][0];
		else
			Rev(v),v=parent[v][0];
}

inline void Change(int x,int y)
{
	if (vst[x])
	{
		Rev(x); C[x]=y; Rev(x);
	}
	else C[x]=y;
}

int ans[50005];

inline void Solve()
{
	Block::init(n);
	int lca;
	for (int i=1;i<=Q[1].t;i++)
		Change(X[i].x,X[i].y);
	T(Q[1].u,Q[1].v);
	lca=LCA(Q[1].u,Q[1].v);
	Rev(lca);
	ans[Q[1].idx]=Block::query();
	Rev(lca);
	for (int i=2;i<=cnt1;i++)
	{
		for (int j=Q[i-1].t+1;j<=Q[i].t;j++)
			Change(X[j].x,X[j].y);
		for (int j=Q[i-1].t;j>Q[i].t;j--)
			Change(X[j].x,X[j].pre);
		T(Q[i-1].u,Q[i].u);
		T(Q[i-1].v,Q[i].v);
		lca=LCA(Q[i].u,Q[i].v);
		Rev(lca);
		ans[Q[i].idx]=Block::query();
		Rev(lca);
	}
}

int main()
{
	int _u,_v,order;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(n); read(m);
	for (int i=1;i<=n;i++)
		read(C[i]),ihead[i]=C[i];
	for (int i=1;i<n;i++)
	{
		read(_u); read(_v); 
		add(_u,_v,++inum); add(_v,_u,++inum);
	}
	dfs(1,0);
	B=pow(n,2.0/3);
	find(1,0);
	while (top) pos[Stk[top--]]=bot;
	for (int i=1;i<=m;i++)
	{
		read(order); read(_u); read(_v);
		if (!order)
		{
			X[++cnt2].x=_u; X[cnt2].y=_v; X[cnt2].t=i; X[cnt2].pre=ihead[_u]; ihead[_u]=_v;
		}
		else
		{
			Q[++cnt1].u=_u; Q[cnt1].v=_v; Q[cnt1].t=cnt2; Q[cnt1].idx=cnt1;
			if (pre[Q[cnt1].u]>pre[Q[cnt1].v]) swap(Q[cnt1].u,Q[cnt1].v);
		}
	}
	sort(Q+1,Q+cnt1+1,cmp);
	Solve();
	for (int i=1;i<=cnt1;i++)
		printf("%d\n",ans[i]);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值