【洛谷 P3348】【ZJOI2016】—大森林(LCT)
考虑离线下来从左往右做
可以先把每个位置的修改加上之后再一起询问
对于每次的生长节点的修改
考虑新建一个虚点
每次加一个点就直接接在前一个虚点后面
这样每次不同的生长节点就只需要和当前父亲断开接到上
询问可以用的方法差分
找可以2次得到
#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ob==ib)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
#define bg begin
#define poly vector<int>
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int N=300005;
struct opt{
int op,u,v,pri;
opt(int _o=0,int _u=0,int _v=0,int _p=0):op(_o),u(_u),v(_v),pri(_p){}
friend inline bool operator <(cs opt &a,cs opt &b){
return a.op==b.op?a.op<b.op:a.pri<b.pri;
}
};
vector<opt> p[N];
int n,m;
namespace Lct{
int val[N],s[N],son[N][2],fa[N],rev[N],tot;
#define lc(u) son[u][0]
#define rc(u) son[u][1]
inline int initnode(int k){
int u=++tot;val[u]=s[u]=k;
return u;
}
inline bool isrt(int u){
return fa[u]?(lc(fa[u])!=u&&rc(fa[u])!=u):1;
}
inline bool isrc(int u){
return rc(fa[u])==u;
}
inline void pushup(int u){
s[u]=val[u];
if(lc(u))s[u]+=s[lc(u)];
if(rc(u))s[u]+=s[rc(u)];
}
inline void rotate(int v){
int u=fa[v],z=fa[u];
int t=isrc(v);
if(!isrt(u))son[z][isrc(u)]=v;
fa[v]=z;
fa[son[v][t^1]]=u;
son[u][t]=son[v][t^1];
fa[u]=v,son[v][t^1]=u;
pushup(u),pushup(v);
}
inline void splay(int u){
while(!isrt(u)){
if(!isrt(fa[u]))
isrc(u)==isrc(fa[u])?rotate(fa[u]):rotate(u);
rotate(u);
}
}
inline int access(int u){
int v;
for(v=0;u;v=u,u=fa[u]){
splay(u),rc(u)=v;
if(v)fa[v]=u;
pushup(u);
}
return v;
}
inline void link(int u,int v){
splay(u),fa[u]=v;
}
inline void cut(int u){
access(u),splay(u),fa[lc(u)]=0,lc(u)=0;pushup(u);
}
inline int query(int u,int v){
int res=0;
access(u),splay(u),res+=s[u];
int lca=access(v);splay(v),res+=s[v];
access(lca),splay(lca),res-=2*s[lca];
return res;
}
}
int L[N],R[N],id[N],tot,last,cnt;
int ans[N];
int main(){
n=read(),m=read();
Lct::initnode(0),L[1]=1,R[1]=n,id[tot=1]=1;
Lct::initnode(0),Lct::link(2,1),last=2;
for(int i=1;i<=m;i++){
int op=read();
if(op==0){
int l=read(),r=read();
L[++tot]=l,R[tot]=r;
id[tot]=Lct::initnode(1);
Lct::link(id[tot],last);
}
else if(op==1){
int l=read(),r=read(),x=read();
l=max(l,L[x]),r=min(r,R[x]);
if(l>r)continue;
int now=Lct::initnode(0);
Lct::link(now,last);
p[l].pb(opt(1,now,id[x],i));
p[r+1].pb(opt(1,now,last,i));
last=now;
}
else{
int x=read(),u=read(),v=read();
p[x].pb(opt(2,id[u],id[v],i));
}
}
memset(ans,-1,sizeof(ans));
for(int i=1;i<=n;i++){
sort(p[i].bg(),p[i].end());
for(opt &x:p[i]){
if(x.op==1)Lct::cut(x.u),Lct::link(x.u,x.v);
else ans[x.pri]=Lct::query(x.u,x.v);
}
}
for(int i=1;i<=m;i++)if(ans[i]!=-1)cout<<ans[i]<<'\n';
}