2022.7.31记录

分散层叠思想:

将后续信息融入到当前查询中,利用当前查询结果定位后续查询结果

四毛子思想:

对数分块,直接打表所有可能面对的情况,最后分块查表即可

+-1RMQ问题,01矩阵乘法问题,LCA,配合笛卡尔树可以完成任意RMQ问题

(突然发现自己以前出的一道无结合律的线段树就是四毛子)

最小差值生成树:

wssb,排序直接加边,破圈法用当前边代替换上最小边,统计一下存在的边极差即可

[NOI2014]魔法森林:

枚举a,把所有小于a的边加入,维护关于b的最小生成树,维护1~n路径上最大的b值

 [BJOI2014]大融合:

LCT,统计一下删边后两连通块的大小

[SDOI2017]树点涂色

LCT+树链剖分

Access操作时把LCT虚变实的边的下子树权值-1,实变虚的边的下子树的权值+1

本质上是由LCT确定维护的区间,然后在dfs序的线段树上维护最大值

一个防止findroot的方法,在LCT中维护dep最小的点的编号

代码:(老了,首先是fir[u]写成了fir[p],调了一个小时,然后是线段树懒标记下传写错,又调了一个小时,再是rot少写了更新z节点的语句,又调了半个小时,麻中麻)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
    char c;int num=0,flg=1;
    while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
    while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
    return num*flg;
}
#define N 100005
int to[2*N],nxt[2*N],fir[N],cnt;
void adde(int a,int b)
{
    to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;
}
int siz[N],son[N],top[N],fa[N],dep[N];
int dfn[N],num[N],dc;
void dfs1(int u,int f)
{
    fa[u]=f;
    dep[u]=dep[f]+1;
    siz[u]=1;
    for(int v,p=fir[u];p;p=nxt[p]){
        if((v=to[p])!=f){
            dfs1(v,u);
            siz[u]+=siz[v];
            if(siz[son[u]]<siz[v])
                son[u]=v;
        }
    }
}
void dfs2(int u)
{
    dfn[u]=++dc;num[dc]=u;
    if(son[u]){
        top[son[u]]=top[u];
        dfs2(son[u]);
    }
    for(int v,p=fir[u];p;p=nxt[p]){
        v=to[p];
        if(v!=son[u]&&v!=fa[u]){
            top[v]=v;
            dfs2(v);
        }
    }
}
int LCA(int u,int v)
{
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]])
            swap(u,v);
        u=fa[top[u]];
    }
    return dep[u]<dep[v]?u:v;
}
struct node{
    int l,r,mx,la;
}a[4*N];
void pushup(int i)
{
    a[i].mx=max(a[i<<1].mx,a[i<<1|1].mx);
}
void build(int i,int l,int r)
{
    a[i].l=l;a[i].r=r;
    if(l==r){
        a[i].mx=dep[num[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    pushup(i);
}
void pushdown(int i)
{
    if(a[i].l==a[i].r)return;
    if(a[i].la){
        a[i<<1].mx+=a[i].la;
        a[i<<1|1].mx+=a[i].la;
        a[i<<1].la+=a[i].la;
        a[i<<1|1].la+=a[i].la;
        a[i].la=0;
    }
}
void update(int i,int l,int r,int k)
{
    if(a[i].l>r||a[i].r<l)return;
    pushdown(i);
    if(l<=a[i].l&&a[i].r<=r){
        a[i].mx+=k;
        a[i].la+=k;
        return;
    }
    update(i<<1,l,r,k);
    update(i<<1|1,l,r,k);
    pushup(i);
}
int query(int i,int l,int r)
{
    if(a[i].l>r||a[i].r<l) return 0;
    pushdown(i);
    if(l<=a[i].l&&a[i].r<=r)
        return a[i].mx;
    return max(query(i<<1,l,r),query(i<<1|1,l,r));
}
namespace LCT{
    int ch[N][2],fa[N],mipos[N];
    void pushup(int x)
    {
        mipos[x]=x;
        if(ch[x][0]&&dep[mipos[ch[x][0]]]<dep[mipos[x]])
            mipos[x]=mipos[ch[x][0]];
        if(ch[x][1]&&dep[mipos[ch[x][1]]]<dep[mipos[x]])
            mipos[x]=mipos[ch[x][1]];
    }
    bool pdc(int x){return ch[fa[x]][1]==x;}
    bool pdr(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
    void rot(int x)
    {
        int y=fa[x],z=fa[y];
        bool flg=pdc(x);
        if(!pdr(y)) ch[z][pdc(y)]=x;
        if(ch[y][flg]=ch[x][flg^1])
            fa[ch[y][flg]]=y;
        ch[x][flg^1]=y;
        fa[y]=x;fa[x]=z;
        pushup(y);pushup(x);
    }
    void splay(int x,int y)
    {
        for(;!pdr(x);rot(x))
            if(!pdr(fa[x]))
                rot(pdc(x)==pdc(fa[x])?fa[x]:x);
    }
    int findroot(int x)
    {
        while(ch[x][0])x=ch[x][0];
        return x;
    }
    void Access(int x)
    {
        int tmp=0;
        for(;x;x=fa[x]){
            splay(x,0);
            if(ch[x][1]){
                int rt=mipos[ch[x][1]];
                //int rt=findroot(ch[x][1]);
                update(1,dfn[rt],dfn[rt]+siz[rt]-1,1); 
            }
            if(tmp){
                int rt=mipos[tmp];
                //int rt=findroot(tmp);
                update(1,dfn[rt],dfn[rt]+siz[rt]-1,-1); 
            }
            ch[x][1]=tmp;
            pushup(x);
            tmp=x;
        }
    }
}
int main()
{
    int n,m,x,y,i,op;
    n=gi();m=gi();
    for(i=1;i<n;i++){
        x=gi();y=gi();
        adde(x,y);adde(y,x);
    }
    dfs1(1,0);
    top[1]=1;
    dfs2(1);
    build(1,1,n);
    for(i=1;i<=n;i++)
        LCT::fa[i]=fa[i];
    while(m--){
        op=gi();
        if(op==1){
            x=gi();
            LCT::Access(x);
        }
        else if(op==2){
            x=gi();y=gi();
            int lca=LCA(x,y);
            int ans=query(1,dfn[x],dfn[x])+query(1,dfn[y],dfn[y])-2*query(1,dfn[lca],dfn[lca])+1;
            printf("%d\n",ans);
        }
        else{
            x=gi();
            printf("%d\n",query(1,dfn[x],dfn[x]+siz[x]-1));
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值