bzoj3757似乎因为版权挂了
首先,我们要熟悉序列莫队
然后考虑树上莫队
我们用(l,r)表示当前l到r这条链上的答案(不包括lca),现在考虑从(l,r)转移到(L,R)
我们发现,(l,r)=ans(root,l) xor ans(root,r) ,这样正好去掉了 lca
那么我们这样考虑: (root,l)−>(root,L)
继续观察发现, (root,l)−>(root,L)是将(l,L)反色了
那么算法出现了,初始区间(root,root),每次转移都是将某条链除去lca反色
这样我们就可以很方便的上莫队算法了
关于树分块:
据说用王室联邦的分块会更快,我偷懒用了 dfs 序分块,反正复杂度一样
关于修改:
我们按 n23 分块,排序的时候左端点的块为第一关键字,右端点块为第二关键字,时间为第三关键字,
这样复杂度是 O((N+Q)53) 的
bzoj 3757
//Code by liuchenrui
#include
const int N=50010,P=300;
using namespace std;
inline void splay(int &v){
v=0;char c=0;int p=1;
while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();}
while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();}
v*=p;
}
int to[N*2],nxt[N*2],fir[N],sz,a[N],Ans[N*2],sub[N],tot,dep[N],tt[N][17];
void add(int x,int y){
nxt[++sz]=fir[x],fir[x]=sz,to[sz]=y;
}
void dfs(int x,int fa){
tt[x][0]=fa;sub[x]=++tot;dep[x]=dep[fa]+1;
for(int i=1;i<=16;i++){
tt[x][i]=tt[tt[x][i-1]][i-1];
}
for(int u=fir[x];u;u=nxt[u]){
if(to[u]!=fa){
dfs(to[u],x);
}
}
}
int lca(int x,int y){
if(dep[x]y])swap(x,y);
for(int i=16;~i;i--){
if(dep[tt[x][i]]>=dep[y]){
x=tt[x][i];
}
}
if(x==y)return x;
for(int i=16;~i;i--){
if(tt[x][i]!=tt[y][i]){
x=tt[x][i];
y=tt[y][i];
}
}
return tt[x][0];
}
struct qr{
int l,r,a,b,id;
bool operator<(const qr&x)const{
if(sub[l]/P!=sub[x.l]/P)return sub[l]
}q[N*2];
int stk[N],top,t[N],ans,vis[N],n,Q;
void add(int x){
t[a[x]]++;
if(t[a[x]]==1)ans++;
}
void del(int x){
t[a[x]]--;
if(t[a[x]]==0)ans--;
}
void change(int x,int y){
int _x=x,_y=y;
top=0;
while(x!=y){
if(dep[x]>dep[y])stk[++top]=x,x=tt[x][0];
else stk[++top]=y,y=tt[y][0];
}
for(int i=1;i<=top;i++){
if(stk[i]==x)continue;
vis[stk[i]]++;
if(vis[stk[i]]&1)add(stk[i]);
else del(stk[i]);
}
}
int main(){
splay(n),splay(Q);
for(int i=1;i<=n;i++)splay(a[i]);
for(int i=1;i<=n;i++){
int x,y;splay(x),splay(y);
if(x&&y)add(x,y),add(y,x);
}
dfs(1,0);
for(int i=1;i<=Q;i++){
splay(q[i].l),splay(q[i].r);
splay(q[i].a),splay(q[i].b);
q[i].id=i;
}
sort(q+1,q+Q+1);
int l=1,r=1;
for(int i=1;i<=Q;i++){
change(l,q[i].l);l=q[i].l;
change(r,q[i].r);r=q[i].r;
add(lca(l,r));
if(t[q[i].a]&&t[q[i].b]&&q[i].a!=q[i].b)Ans[q[i].id]=ans-1;
else Ans[q[i].id]=ans;
del(lca(l,r));
}
for(int i=1;i<=Q;i++){
printf("%d\n",Ans[i]);
}
}
bzoj4129
//Code by liuchenrui
#include
const int N=50010,P=1300,P2=233;
using namespace std;
inline void splay(int &v){
v=0;char c=0;int p=1;
while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();}
while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();}
v*=p;
}
int to[N*2],nxt[N*2],fir[N],sz,a[N],Ans[N];
int sub[N],tot,dep[N],tt[N][18],_a[N],isq[N],m;
int stk[N],top,vis[N],n,Q,f[N],t[N],s[N];
void add(int x,int y){
nxt[++sz]=fir[x],fir[x]=sz,to[sz]=y;
}
void dfs(int x,int fa){
tt[x][0]=fa;sub[x]=++tot;dep[x]=dep[fa]+1;
for(int i=1;i<=17;i++){
tt[x][i]=tt[tt[x][i-1]][i-1];
}
for(int u=fir[x];u;u=nxt[u]){
if(to[u]!=fa){
dfs(to[u],x);
}
}
}
int lca(int x,int y){
if(dep[x]y])swap(x,y);
for(int i=17;~i;i--){
if(dep[tt[x][i]]>=dep[y]){
x=tt[x][i];
}
}
if(x==y)return x;
for(int i=17;~i;i--){
if(tt[x][i]!=tt[y][i]){
x=tt[x][i];
y=tt[y][i];
}
}
return tt[x][0];
}
namespace ans{
int t[N],blo[N],l[N],r[N],bel[N],cnt;
int add(int x){
x=::a[x];
t[x]++;
if(t[x]==1)blo[bel[x]]++;
}
int del(int x){
x=::a[x];
t[x]--;
if(t[x]==0)blo[bel[x]]--;
}
int getans(){
for(int i=1;i<=cnt;i++){
if(blo[i]!=r[i]-l[i]+1){
for(int j=l[i];j<=r[i];j++){
if(!t[j])return j;
}
}
}
}
void init(){
int p=0;
for(int i=0;i<=::n+1;i++){
if(i/P2+1!=p){
p=i/P2+1;
l[++cnt]=i;
r[cnt-1]=i-1;
}
bel[i]=cnt;
}
r[cnt]=n+1;
}
}
struct qr{
int l,r,v,id;
bool operator<(const qr&x)const{
if(sub[l]/P!=sub[x.l]/P)return sub[l]
}q[N];
void change(int x,int y){
int _x=x,_y=y;
top=0;
while(x!=y){
if(dep[x]>dep[y])stk[++top]=x,x=tt[x][0];
else stk[++top]=y,y=tt[y][0];
}
for(int i=1;i<=top;i++){
if(stk[i]==x)continue;
vis[stk[i]]++;
if(vis[stk[i]]&1)ans::add(stk[i]);
else ans::del(stk[i]);
}
}
int main(){
splay(n),splay(Q);
for(int i=1;i<=n;i++){
splay(a[i]);
if(a[i]>n+1)a[i]=n+1;
}
for(int i=1;iint x,y;splay(x),splay(y);
add(x,y),add(y,x);
}
dfs(1,0);
int cnt=0;
memcpy(_a,a,sizeof a);
for(int i=1;i<=Q;i++){
int op;splay(op);
if(op){
splay(q[++m].l),splay(q[m].r);
q[m].v=cnt;q[m].id=i;
isq[i]=1;
}
else{
splay(f[++cnt]);
s[cnt]=_a[f[cnt]];
splay(t[cnt]);
if(t[cnt]>n+1)t[cnt]=n+1;
_a[f[cnt]]=t[cnt];
}
}
sort(q+1,q+m+1);
ans::init();
int l=1,r=1,tim=0;;
for(int i=1;i<=m;i++){
change(l,q[i].l);l=q[i].l;
change(r,q[i].r);r=q[i].r;
while(tim<q[i].v){
++tim;
if(vis[f[tim]]&1)ans::del(f[tim]);
a[f[tim]]=t[tim];
if(vis[f[tim]]&1)ans::add(f[tim]);
}
while(tim>q[i].v){
if(vis[f[tim]]&1)ans::del(f[tim]);
a[f[tim]]=s[tim];
if(vis[f[tim]]&1)ans::add(f[tim]);
--tim;
}
ans::add(lca(l,r));
Ans[q[i].id]=ans::getans();
ans::del(lca(l,r));
}
for(int i=1;i<=Q;i++){
if(isq[i]){
printf("%d\n",Ans[i]);
}
}
}