@11101001
2018-03-24T13:32:57.000000Z
字数 3212
阅读 865
数据结构.....大概很容易看出是道lct 然后弃疗
操作1很想lct里面的access操作
那么对于操作2
设F[i]=i点到lct根路径上的splay数(也就是虚边数)+1
那么对于操作2的(x,y)
ans(x,y)=F[x]+F[y]-(F(lca(x,y)))+1;
对于操作3的(x),就是在x的子树中取max,我们可以用dfs序+线段树维护
考虑操作1对操作3的影响
在access的时候,当一个边由虚变实,此时该边所连的深度大的点的颜色种类-1
反之当一边由实变虚,此时该边所连的深度大的点的颜色种类+1
trick:保存当前节点在树中最左儿子的编号用以修改区间(即left[])
ps:中途电脑爆炸,然后重码QAQ,心态爆炸
/*** 数据结构+LCT+SEG_TREE**/#include<cstdio>#include<algorithm>const int maxn = 100007;int n,m;struct node{int v,next;}edge[maxn<<1];int head[maxn],num;void Add_Edge(int u,int v) {edge[++num].v=v;edge[num].next=head[u];head[u]=num;}int idfn[maxn],ldfn[maxn],rdfn[maxn],f[maxn][20],dep[maxn];int cnt=0,fa[maxn];void dfs(int u,int F) {idfn[ldfn[u]=++cnt]=u,f[u][0]=fa[u]=F;for(int i=head[u];i;i=edge[i].next) {int v=edge[i].v;if(v!=F) dep[v]=dep[u]+1,dfs(v,u);}rdfn[u]=cnt;return ;}int LCA(int x,int y) {if(dep[x]<dep[y]) std::swap(x,y);for(int i=dep[x]-dep[y],j=0;i;i>>=1,++j)if(i&1)x=f[x][j];if(x==y) return x;for(int i=19;~i;--i)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];return f[x][0];}class Segment_Tree {#define lc x<<1#define rc x<<1|1private :struct Node {int max,tag;Node () : tag(0){}};Node t[maxn<<2];void update(int x) {t[x].max=std::max(t[lc].max,t[rc].max);}void push_down(int x) {if(!t[x].tag)return;int k=t[x].tag;t[lc].max+=k;t[lc].tag+=k;t[rc].max+=k;t[rc].tag+=k;t[x].tag=0;return ;}public :void build (int x,int l,int r) {if(l==r) {t[x].max=dep[idfn[l]]+1;return;}int mid=l+r>>1;build(lc,l,mid);build(rc,mid+1,r);return update(x);}void modify(int x,int l,int r,int L,int R,int w) {if(L<=l&&R>=r) {t[x].tag+=w;t[x].max+=w;return ;}push_down(x);int mid=l+r>>1;if(mid>=L) modify(lc,l,mid,L,R,w);if(mid<R) modify(rc,mid+1,r,L,R,w);return update(x);}int query(int x,int l,int r,int L,int R) {if(L<=l&&R>=r)return t[x].max;push_down(x);int mid=l+r>>1,ans=0;if(mid>=L) ans=std::max(ans,query(lc,l,mid,L,R));if(mid<R) ans=std::max(ans,query(rc,mid+1,r,L,R));return ans;}#undef lc#undef rc}SEG_T;class Link_Cut_tree {#define lc ch[x][0]#define rc ch[x][1]private :int ch[maxn][2],left[maxn];void update(int x) {left[x]=lc ? left[lc]:x;}bool isroot(int x) {return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}void rotate(int x) {int y=fa[x],z=fa[y],d=(ch[y][1]==x)^1;if(!isroot(y)) ch[z][ch[z][1]==y]=x;fa[x]=z;ch[y][d^1]=ch[x][d],fa[ch[x][d]]=y;ch[x][d]=y;fa[y]=x;update(y),update(x);}void splay(int x) {while(!isroot(x)) {int y=fa[x],z=fa[y];if(!isroot(y)) {if(ch[y][1]==x^ch[z][1]==y) rotate(x);else rotate(y);}rotate(x);}}public:void init() {dfs(1,0),SEG_T.build(1,1,n);for(int i=1;i<=n;++i) left[i]=i;for(int j=1;j<20;j++)for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];}void access(int x) {for(int t=0;x;x=fa[t=x]) {splay(x);if(rc) SEG_T.modify(1,1,n,ldfn[left[rc]],rdfn[left[rc]],1);rc=t;if(rc) SEG_T.modify(1,1,n,ldfn[left[rc]],rdfn[left[rc]],-1);}return ;}int query(int x) {int ans=0;for(;x;x=fa[x],ans++)splay(x);return ans;}int query(int u,int v) {return query(u)+query(v)-2*query(LCA(u,v))+1;}#undef lc#undef rc}LCT;int main() {// freopen("001.out","w",stdout);scanf("%d%d",&n,&m) ;for(int a,b,i=1;i<n;++i) {scanf("%d%d",&a,&b);Add_Edge(a,b);Add_Edge(b,a);}LCT.init();for(int opt,x,y,i=1;i<=m;++i) {scanf("%d",&opt);if(opt==1) scanf("%d",&x),LCT.access(x);if(opt==2) scanf("%d%d",&x,&y),printf("%d\n",LCT.query(x,y));else if(opt==3) scanf("%d",&x),printf("%d\n",SEG_T.query(1,1,n,ldfn[x],rdfn[x]));}return 0;}