题解:P4116 Qtree3
观测到题解区没有树上带修莫队做法,我来写一篇。
本题有两种操作,要求维护单点翻转和路径深度最小的黑点(以点
时间复杂度
本题不卡常,放心做。
:::info[如果你不知道树上莫队]
对树进行 dfs,每个点
下面考虑一条路径
-
当
\text{lca}(u,v)=u 时,序列上从f_u 到f_v 的区间内,(u,v) 路径上的节点恰好出现1 次,其他不在路径上的节点出现0 或2 次。 -
当
\text{lca}(u,v)\ne u 时,序列上从g_u 到f_v 的区间内,(u,v) 路径上的节点除\text{lca}(u,v) 外恰好出现1 次,其他节点出现0 或2 次,此时把\text{lca}(u,v) 特判一下加入就可以了。
| 因为无用节点出现 |
|---|
其实跑得还不算很慢,最慢点两百毫秒。
:::success[code]
#include<bits/stdc++.h>
#define int unsigned int
#define endl '\n'
#define pb push_back
using namespace std;
const int N=2e6+5;
const int B2=450;
int n,m,B,a[N],b[N],idx,cnt[N],id[N],f[N],g[N],fa[N],dfn[N],top[N],siz[N],dep[N],son[N],cntq,cntu,last[N],cur,ans[N],vb[N];
bool vis[N];
int cntdep[N],vb2[N],depn[N];
struct qry{
int l,r,t,x,typ,lca;
}q[N];
struct upd{
int x;
}up[N];
bool cmp(qry a,qry b){
if(a.l/B!=b.l/B) return a.l<b.l;
else if(a.r/B!=b.r/B){
if(a.l/B&1) return a.r<b.r;
else return a.r>b.r;
}
else{
if(a.r/B&1) return a.t<b.t;
else return a.t>b.t;
}
}
vector<int> G[N];
void dfs1(int x,int ft){
id[f[x]=++idx]=x;
dep[x]=dep[ft]+1;
siz[x]=1;
fa[x]=ft;
for(auto i:G[x]){
if(i==ft) continue;
dfs1(i,x);
siz[x]+=siz[i];
if(siz[i]>siz[son[x]]) son[x]=i;
}
id[g[x]=++idx]=x;
}
void dfs2(int x,int tp){
top[x]=tp;
if(son[x]) dfs2(son[x],tp);
for(auto i:G[x]) if(i!=fa[x]&&i!=son[x]) dfs2(i,i);
}
int lca(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 x;
}
inline void insert(int x){
int d=dep[x];
if(cntdep[d]==0) vb2[d/B2]++;
cntdep[d]++;
depn[d]=x;
}
inline void erase(int x){
int d=dep[x];
cntdep[d]--;
if(cntdep[d]==0) vb2[d/B2]--;
}
inline int query(){
for(int b=0;b<=n/B2+1;b++){
if(vb2[b]){
int R=min(n,(b+1)*B2-1);
for(int d=b*B2;d<=R;d++){
if(cntdep[d]) return depn[d];
}
}
}
return -1;
}
inline void add(int x){
if(vis[x]){
if(a[x]) erase(x);
vis[x]=0;
}else{
if(a[x]) insert(x);
vis[x]=1;
}
}
inline void update(int x){
if(vis[x]){
if(a[x]) erase(x);
a[x]=a[x]^1;
if(a[x]) insert(x);
}else a[x]=a[x]^1;
}
char ibuf[1<<20],*p1=ibuf,*p2=ibuf;
#define gc() (p1==p2&&(p2=(p1=ibuf)+fread(ibuf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
inline int read(){
int x=0,f=1;char c=gc();
while(c<'0'||c>'9'){ if(c=='-') f=-1; c=gc(); }
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48), c=gc();
return x*f;
}
char obuf[1<<20],*pp=obuf;
inline void push(char c){
if(pp-obuf==(1<<20))fwrite(obuf,1,1<<20,stdout),pp=obuf;
*pp++=c;
}
inline void write(signed x){
if(x<0){ push('-'); x=-x; }
static signed st[12]; signed top=0;
if(!x) push('0');
while(x) st[++top]=x%10, x/=10;
while(top) push(st[top--]^48);
push('\n');
}
inline void readstr(char *s){
char c=gc();
while(c<=' ') c=gc();
while(c>' ') *s++=c, c=gc();
*s=0;
}
signed main(){
n=read();
m=read();
for(int i=1,u,v;i<n;i++){
u=read();
v=read();
G[u].pb(v);
G[v].pb(u);
}
dfs1(1,0);
dfs2(1,1);
for(int i=1,v,op;i<=m;i++){
op=read();
v=read();
if(op==1){
int L=lca(1,v);
q[++cntq]={L==1?f[1]:g[1],f[v],cntu,cntq,1,L};
}
else{
up[++cntu]={v};
}
}
B=pow(2*n,2.0/3)*pow(cntu,1.0/3)/pow(cntq,1.0/3);
sort(q+1,q+cntq+1,cmp);
int r=0,t=0;
for(int i=1;i<=cntq;i++){
while(r<q[i].r) add(id[++r]);
while(r>q[i].r) add(id[r--]);
while(t<q[i].t) t++,update(up[t].x);
while(t>q[i].t) update(up[t].x),t--;
add(1);
ans[q[i].x]=query();
add(1);
}
for(int i=1;i<=cntq;i++) write((signed)ans[i]);
fwrite(obuf,1,pp-obuf,stdout);
return 0;
}
:::