解析
本题需要用LCT维护子树大小
然后我就不会了
然后我就用树剖水过去了
又快又好写,真香
现在详细聊聊如何用LCT维护子树信息
每个结点再定义一个新的变量记录所有虚儿子的信息
然后…完了?
告别盲目pushup,我们来详细聊聊在哪里需要更新虚儿子的信息
毋庸置疑,应该在虚儿子信息改变的时候(废话)
那么什么时候发生改变呢?
- access:虚实边会交换状态,需要更新虚子树状态
- link:增加了虚儿子,需要更新虚子树状态
没了
splay、rotate、makeroot、findroot都是在一个splay里自己玩泥巴,显然不会改变虚儿子的状态
注意cut是减少了一个实儿子,也没有改变虚儿子状态
似乎还不太难对吧
所以,对于LCT的标记问题,我们要理性分析,相信科学
update:
纸上得来终觉浅,绝知此事要躬行
(翻译:不要口胡)
qwq
不自己写一遍是真的找不到坑点…
这里的link改变虚子树状态的时候,会连带上面一串splay的信息都出问题!
而且由于其他地方默认的是原来的信息正确,因此这里即使后面splay或makeroot也于事无补
解决办法是把y转到根再更新其虚子树信息
inline void link(int x,int y){makeroot(x);access(y);splay(y);siz0[y]+=siz[x];f[x]=y;pushup(y);return;
}
代码
然而懒得重写,还是贴的我的树剖
明天晨练可以写遍这个
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e5+100;
const int mod=1e9+7;
const double eps=1e-9;
inline ll read() {ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}int n,m;
struct node{int to,nxt;
}p[N<<1];
int fi[N],cnt;
inline void addline(int x,int y){p[++cnt]=(node){y,fi[x]};fi[x]=cnt;return;
}
struct ope{int op,x,y;
}q[N];
struct edge{int x,y;
}e[N];
int tot,fa[N],num[N];
int find(int x){return x==fa[x]?x:find(fa[x]);}
inline void merge(int x,int y){x=find(x);y=find(y);if(num[x]>num[y]) swap(x,y);e[++tot]=(edge){x,y};fa[x]=y;num[y]+=num[x];return;
}int dfn[N],pos[N],tim,f[N],siz[N],hson[N],top[N];
int pl[N][19];
void dfs1(int x,int fa){f[x]=fa;pl[x][0]=fa;for(int k=1;pl[x][k-1];k++) pl[x][k]=pl[pl[x][k-1]][k-1];siz[x]=1;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==fa) continue;dfs1(to,x);siz[x]+=siz[to];if(siz[to]>siz[hson[x]]) hson[x]=to;}return;
}
void dfs2(int x,int tp){top[x]=tp;pos[x]=++tim;dfn[tim]=x;if(hson[x]) dfs2(hson[x],tp);for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f[x]||to==hson[x]) continue;dfs2(to,to);}return;
}int val[N];
inline void add(int p,int w){for(;p<=n;p+=p&-p) val[p]+=w;return;
}
inline int ask(int p){int res(0);for(;p;p-=p&-p) res+=val[p];return res;
}
void init(){for(int i=1;i<=n;i++){add(pos[i],siz[i]);add(pos[i]+1,-siz[i]);}return;
}void upd(int x,int anc,int w){while(top[x]!=top[anc]){add(pos[top[x]],w);add(pos[x]+1,-w);x=f[top[x]];}add(pos[anc],w);add(pos[x]+1,-w);return;
}ll ans[N];
int o;
int main() {
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifmemset(fi,-1,sizeof(fi));cnt=-1;n=read();m=read();for(int i=1;i<=n;i++) num[i]=1,fa[i]=i;for(int i=1;i<=m;i++){char c;int x,y;scanf(" %c",&c);x=read(),y=read();q[i]=(ope){c=='A',x,y};if(c=='A'){addline(x,y);addline(y,x);merge(x,y);}}for(int i=1;i<=n;i++){if(!siz[i]){dfs1(i,0);dfs2(i,i);}}init();for(int i=m;i>=1;i--){if(q[i].op){int x=e[tot].x,y=e[tot].y;--tot;num[y]-=num[x];fa[x]=x;x=q[i].x,y=q[i].y; if(f[x]==y) swap(x,y);int w=ask(pos[y]);int tp=x,oo=find(x);for(int k=17;k>=0;k--){if(!pl[tp][k]||find(pl[tp][k])!=oo) continue;tp=pl[tp][k];}upd(x,tp,-w);//printf("cut:(%d %d) w=%d tp=%d\n\n",x,y,w,tp);}else{int x=q[i].x,y=q[i].y;if(f[x]==y) swap(x,y);int sum=num[find(x)],bot=ask(pos[y]);ans[++o]=1ll*bot*(sum-bot);//printf("(%d %d):sum=%d bot=%d\n\n",x,y,sum,bot);}}while(o) printf("%lld\n",ans[o--]);return 0;
}
/*
8 12
A 2 3
Q 2 3
A 3 4
Q 2 3
A 3 8
Q 3 8
Q 3 4
Q 2 3
A 8 7
A 6 5
Q 8 7
Q 5 6*/