bzoj 4530: [Bjoi2014]大融合 lct维护子树信息

xiaoxiao2021-02-28  50

题意

给你n个点,要求资瓷以下操作: A x y连接x和y。 Q x y询问x所在的树上有多少条简单路径经过x到y这条边。 n,m<=100000

分析

lct维护子树信息 这题显然是要动态维护每个点的size。 考虑如何用lct维护子树大小。 定义siz[x]表示x的所有虚儿子的子树大小和,size[x]表示x的所有虚儿子+实儿子+自己的子树大小和。那么只要在虚实边变化的时候维护一下siz的大小,同时维护size就好了。 求x的子树大小,只要access(x),然后siz[x]+1就是答案了。

代码

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<stack> using namespace std; typedef long long LL; const int N=100005; int n,m; struct tree{int siz,size,l,r,fa,rev;}t[N]; stack<int> sta; int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } bool is_root(int x) { return !t[x].fa||(x!=t[t[x].fa].l&&x!=t[t[x].fa].r); } void updata(int x) { t[x].size=t[t[x].l].size+t[t[x].r].size+t[x].siz+1; } void pushdown(int x) { if (!t[x].rev) return; t[x].rev^=1;swap(t[x].l,t[x].r); if (t[x].l) t[t[x].l].rev^=1; if (t[x].r) t[t[x].r].rev^=1; } void rttr(int x) { int y=t[x].l; t[x].l=t[y].r;t[t[y].r].fa=x; if (x==t[t[x].fa].l) t[t[x].fa].l=y; else if (x==t[t[x].fa].r) t[t[x].fa].r=y; t[y].fa=t[x].fa; t[y].r=x;t[x].fa=y; updata(x);updata(y); } void rttl(int x) { int y=t[x].r; t[x].r=t[y].l;t[t[y].l].fa=x; if (x==t[t[x].fa].l) t[t[x].fa].l=y; else if (x==t[t[x].fa].r) t[t[x].fa].r=y; t[y].fa=t[x].fa; t[y].l=x;t[x].fa=y; updata(x);updata(y); } void remove(int x) { while (!is_root(x)) sta.push(x),x=t[x].fa; pushdown(x); while (!sta.empty()) x=sta.top(),sta.pop(),pushdown(x); } void splay(int x) { remove(x); while (!is_root(x)) { int p=t[x].fa,g=t[p].fa; if (is_root(p)) { if (x==t[p].l) rttr(p); else rttl(p); break; } if (x==t[p].l) if (p==t[g].l) rttr(g),rttr(p); else rttr(p),rttl(g); else if (p==t[g].r) rttl(g),rttl(p); else rttl(p),rttr(g); } } void access(int x) { int p=0; while (x) { splay(x); t[x].siz+=t[t[x].r].size; t[x].r=p; t[x].siz-=t[p].size; updata(x); p=x;x=t[x].fa; } } void make_root(int x) { access(x);splay(x);t[x].rev^=1; } void link(int x,int y) { make_root(x);make_root(y);t[x].fa=y;t[y].siz+=t[x].size;updata(y); } int main() { n=read();m=read(); for (int i=1;i<=n;i++) t[i].size=1; while (m--) { char ch[2]; scanf("%s",ch); int x=read(),y=read(); if (ch[0]=='A') link(x,y); else { make_root(x);access(y);splay(x); printf("%lld\n",(LL)(t[y].siz+1)*(t[x].size-t[y].siz-1)); } } return 0; }
转载请注明原文地址: https://www.6miu.com/read-55229.html

最新回复(0)