您的位置:首页 > 其它

[树上莫队] BZOJ 3757 3052 4129

2016-02-16 16:09 183 查看
传送门

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
;
}
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: