BS4150【NOI2014模拟17】花园(树剖,线段树,差分)
这道题可以差分然后线段树询问来做,同时也可以直接树剖然后在线段树内部用 set 维护。
可知线段树树高严格 (logn) ,所以单次修改是 (O(log^3n)) ,查询是 (O(log^2n)) ,1e5的数据比较卡,可以用差分的思路变成 2log 。
代码:
#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
x=0;char ch=getchar();bool f=false;
while(!isdigit(ch)) f|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x=f?-x:x;
}
template <typename T>
inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^48);
}
const int N=1e6+5;
#define ll long long
int n,m,root;
int head[N],nex[N],to[N],idx,val[N];
int dep[N],siz[N],son[N],fa[N],dfn[N],top[N],rev[N],tot;
multiset<int>S[N<<2];
void Add(int u,int v){
nex[++idx]=head[u];
to[idx]=v;
head[u]=idx;
return ;
}
void Dfs1(int x,int f){
siz[x]=1,fa[x]=f,dep[x]=dep[f]+1;
for(int i=head[x];i;i=nex[i]){
int y=to[i];
if(y==f) continue;
Dfs1(y,x);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]]) son[x]=y;
}
return ;
}
void Dfs2(int x){
if(x==son[fa[x]]) top[x]=top[fa[x]];
else top[x]=x;
dfn[x]=++tot;rev[tot]=x;
if(son[x]) Dfs2(son[x]);
for(int i=head[x];i;i=nex[i]){
int y=to[i];
if(y==fa[x]||y==son[x]) continue;
Dfs2(y);
}
return ;
}
int sum[N<<2];
void Pushup(int x){
multiset<int>::iterator it;
for(it=S[x<<1].begin();it!=S[x<<1].end();it++) S[x].insert(*it);
for(it=S[x<<1|1].begin();it!=S[x<<1|1].end();it++) S[x].insert(*it);
sum[x]=S[x].size();
return ;
}
void Update(int x,int lose,int get){
if(lose==get) return ;
while(floor(x>>1)>0){
int f=floor(x>>1);
S[f].erase(S[f].find(lose));
S[f].insert(get);
x=f;
}
return ;
}
void Build(int x,int l,int r){
if(l==r){S[x].insert(val[rev[l]]);return ;}
int mid=l+r>>1;
Build(x<<1,l,mid),Build(x<<1|1,mid+1,r);
Pushup(x);
return ;
}
void Modify(int x,int l,int r,int ql,int qr,int k){
if(ql<=l&&qr>=r){
Update(x,*S[x].begin(),k);
S[x].erase(*S[x].begin());S[x].insert(k);
sum[x]=1;
return ;
}
int mid=l+r>>1;
if(ql<=mid) Modify(x<<1,l,mid,ql,qr,k);
if(qr>mid) Modify(x<<1|1,mid+1,r,ql,qr,k);
return ;
}
int Query(int x,int l,int r,int ql,int qr,int k){
if(ql<=l&&qr>=r){return S[x].count(k);}
int mid=l+r>>1;int res=0;
if(ql<=mid) res+=Query(x<<1,l,mid,ql,qr,k);
if(qr>mid) res+=Query(x<<1|1,mid+1,r,ql,qr,k);
return res;
}
void RoadModify(int x,int y,int k){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
Modify(1,1,n,dfn[top[x]],dfn[x],k);
x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
Modify(1,1,n,dfn[y],dfn[x],k);
return ;
}
ll RoadQuery(int x,int y,int k){
ll res=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
res+=Query(1,1,n,dfn[top[x]],dfn[x],k);
x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
res+=Query(1,1,n,dfn[y],dfn[x],k);
return res;
}
int QueryLCA(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
return y;
}
int main(){
//freopen("tree.in","r",stdin);
//freopen("tree.out","w",stdout);
read(n),read(m);
for(int i=1;i<=n;i++) read(val[i]);
for(int i=1;i<n;i++){
int u,v;
read(u),read(v);
Add(u,v),Add(v,u);
}
root=1;
Dfs1(1,0);
Dfs2(1);
Build(1,1,n);
for(int i=1,x,y,k,las=0;i<=m;i++){
char op[4];
scanf("%s",op);
if(op[0]=='C'){
read(x),read(k);
x^=las,k^=las;
Modify(1,1,n,dfn[x],dfn[x],k);
}
else{
read(x),read(y),read(k);
x^=las,k^=las,y^=las;
las=RoadQuery(x,y,k);
write(las),putchar('
');
}
}
return 0;
}
差分代码:
#include<bits/stdc++.h>
using namespace std;
#define l(x) t[x].l
#define r(x) t[x].r
#define a(x) t[x].add
#define v(x) t[x].val
const int N=1e5+5;
template <typename T>
inline void read(T &x){
x=0;char ch=getchar();bool f=false;
while(!isdigit(ch)) f|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x=f?-x:x;
}
template <typename T>
inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^48);
}
struct Segment_Tree{int l,r,add,val;}t[N*100];
map<int,int> val;
int n,q,ans,sum,size,T[N],root[N<<2];
int tot,top,head[N],to[N<<1],nex[N<<1],dep[N],fa[N][20],dfn[N<<1],b[N],e[N];
void add(int u,int v){nex[++tot]=head[u],head[u]=tot,to[tot]=v;}
void dfs(int x){
dfn[++top]=x;
for(int i=1;i<=16;i++){
if((1<<i)<=dep[x]) fa[x][i]=fa[fa[x][i-1]][i-1];
else break;
}
for(int i=head[x];i;i=nex[i]) if(to[i]!=fa[x][0]) fa[to[i]][0]=x,dep[to[i]]=dep[x]+1,dfs(to[i]);
dfn[++top]=x;
}
int QueryLca(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
int temp=dep[u]-dep[v];
for(int i=0;i<=16;i++) if(temp&(1<<i)) u=fa[u][i];
for(int i=16;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
return u==v?u:fa[u][0];
}
void PushDown(int p,int l,int r){
if(!a(p)||l==r) return;
int temp=a(p);
if(!l(p)) l(p)=++size;
if(!r(p)) r(p)=++size;
a(p)=0,v(l(p))+=temp,a(l(p))+=temp,v(r(p))+=temp,a(r(p))+=temp;
}
void Modify(int &p,int l,int r,int x,int y,int d){
if(!p) p=++size;
PushDown(p,l,r);
if(x==l&&y==r){v(p)+=d,a(p)+=d;return;}
int mid=(l+r)>>1;
if(x<=mid) Modify(l(p),l,mid,x,min(y,mid),d);
if(y>mid) Modify(r(p),mid+1,r,max(x,mid+1),y,d);
}
int Query(int p,int l,int r,int x){
if(!p) return 0;
PushDown(p,l,r);
if(l==r) return v(p);
int mid=(l+r)>>1;
if(x<=mid) return Query(l(p),l,mid,x);
else return Query(r(p),mid+1,r,x);
}
int main(){
read(n),read(q);
for(int i=1;i<=n;i++){
read(T[i]);
if(!val[T[i]]) val[T[i]]=++sum;
T[i]=val[T[i]];
}
for(int i=1,u,v;i<n;i++) read(u),read(v),add(u,v),add(v,u);
dfs(1);
for(int i=1;i<=top;i++){
if(!b[dfn[i]]) b[dfn[i]]=i;
else e[dfn[i]]=i;
}
for(int i=1;i<=n;i++) Modify(root[T[i]],1,top,b[i],e[i],1);
for(int i=1,x,y,z;i<=q;i++){
char op[3];
scanf("%s",op),read(x),read(y),x^=ans,y^=ans;
if(op[0]=='Q'){
read(z),z^=ans;
int Lca=QueryLca(x,y);
if(!val[z]){ans=0,puts("0");continue;}
z=val[z],ans=Query(root[z],1,top,b[x])+Query(root[z],1,top,b[y])-2*Query(root[z],1,top,b[Lca]);
if(T[Lca]==z) ans++;
write(ans),putchar('
');
}
if(op[0]=='C'){
if(!val[y]) val[y]=++sum;
y=val[y],Modify(root[T[x]],1,top,b[x],e[x],-1),Modify(root[y],1,top,b[x],e[x],1),T[x]=y;
}
}
}