Short But Scary 解题报告

Short But Scary

正解的离线分治+虚树的做法太神奇...搞不到

搞一个菜一点的ddp写写,结果调了200年,下次一定写树剖不写lct了,太难调了...

大概就是按sub2那样维护

你每个重链开一个线段树,然后链头把贡献扔给别的重链,然后每次在链上二分位置查一个和差不多了

然后可以拿lct写

但你得搞清楚翻转的时候要翻转的东西比较多,细节也比较多,异常的难写...

算了懒得说了,给我毒瘤死了...


Code:

#include <cstdio>
#include <cctype>
#include <algorithm>
#define ls ch[now][0]
#define rs ch[now][1]
#define fa par[now]
const int N=1e5+10;
template <class T>
void read(T &x)
{
    x=0;char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
int head[N],to[N<<1],Next[N<<1],cnt;
void add(int u,int v)
{
    to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
int n,m;
int ch[N][2],par[N],tag[N];//翻转标记
struct koito_yuu
{
    int siz,is,lef,dat,si;
    //实际大小,子树全是,最左边的点是否是,与父亲关系,虚儿子贡献
}yuu[2][N];
int s[N],tot;
bool isroot(int now){return ch[fa][0]==now||ch[fa][1]==now;}
int identity(int now){return ch[fa][1]==now;}
void connect(int f,int now,int typ){ch[fa=f][typ]=now;}
void Reverse(int now)
{
    tag[now]^=1;
    std::swap(yuu[0][now],yuu[1][now]);
}
void updata(int now)
{
    for(int k=0;k<=1;k++)
    {
        yuu[k][now].is=(yuu[k][ls].is&&yuu[k][now].dat&&yuu[k][rs].is);
        yuu[k][now].siz=yuu[k][ls].siz;
        if(ls)
        {
            yuu[k][now].lef=yuu[k][ls].lef;
            if(yuu[k][ls].is&&yuu[k][now].dat)
            {
                yuu[k][now].siz+=yuu[k][now].si+1;
                if(yuu[k][rs].lef) yuu[k][now].siz+=yuu[k][rs].siz;
            }
        }
        else
        {
            yuu[k][now].lef=yuu[k][now].dat;
            yuu[k][now].siz+=yuu[k][now].si+1;
            if(yuu[k][rs].lef) yuu[k][now].siz+=yuu[k][rs].siz;
        }
    }
}
void pushdown(int now)
{
    if(tag[now])
    {
        if(ls) Reverse(ls);
        if(rs) Reverse(rs);
        tag[now]=0;
    }
}
void Rotate(int now)
{
    int p=fa,typ=identity(now);
    connect(p,ch[now][typ^1],typ);
    if(isroot(p)) connect(par[p],now,identity(p));
    else fa=par[p];
    connect(now,p,typ^1);
    updata(p);
    updata(now);
}
void splay(int now)
{
    while(isroot(now)) s[++tot]=now,now=fa;
    s[++tot]=now;
    while(tot) pushdown(s[tot--]);
    now=s[1];
    for(;isroot(now);Rotate(now))
        if(isroot(fa))
            Rotate(identity(now)^identity(fa)?now:fa);
}
void access(int now)
{
    for(int las=0;now;las=now,now=fa)
    {
        splay(now);
        for(int k=0;k<=1;k++)
        {
            if(yuu[0][rs].lef)
                yuu[k][now].si+=yuu[0][rs].siz;
            if(yuu[0][las].lef)
                yuu[k][now].si-=yuu[0][las].siz;
        }
        rs=las;
        updata(now);
    }
}
void dfs(int now,int f)
{
    yuu[0][now].is=yuu[0][now].lef=yuu[0][now].dat=1;
    //yuu[1][now].is=yuu[1][now].lef=yuu[1][now].dat=1;
    for(int v,i=head[now];i;i=Next[i])
        if((v=to[i])!=f)
            par[v]=now,dfs(v,now),yuu[0][now].si+=yuu[0][v].siz;
    yuu[0][now].siz=yuu[0][now].si+1;
    yuu[1][now].si=yuu[0][now].si;
    yuu[1][now].siz=yuu[0][now].siz;
}
void modi(int u)
{
    access(u);
    splay(u);
    Reverse(u);
}
int query(int now)
{
    pushdown(now);
    if(!rs)
    {
        if(yuu[0][now].dat&&ls) return query(ls)+yuu[0][now].si+1;
        return yuu[0][now].si+1;
    }
    if(yuu[0][rs].is)
    {
        int ret=yuu[0][now].si+1+yuu[0][rs].siz;
        if(yuu[0][now].dat&&now!=1) ret+=query(ls);
        return ret;
    }
    return query(rs);
}
int qry(int u)
{
    access(u);
    splay(u);
    return ((yuu[0][u].dat&&u!=1)?query(ch[u][0]):0)+yuu[0][u].si+1;
}
int main()
{
    freopen("scary.in","r",stdin);
    freopen("scary.out","w",stdout);
    yuu[1][1].dat=yuu[0][0].is=yuu[1][0].is=1;
    read(n),read(m);
    for(int u,v,i=1;i<n;i++) read(u),read(v),add(u,v),add(v,u);
    dfs(1,0);
    for(int op,u,v,i=1;i<=m;i++)
    {
        read(op);
        if(op==1)
        {
            read(u),read(v);
            modi(u),modi(v);
        }
        else
        {
            read(u);
            printf("%d\n",qry(u));
        }
    }
    return 0;
}

2019.3.25

猜你喜欢

转载自www.cnblogs.com/butterflydew/p/10597011.html