BZOJ 2759 一个动态树好题 (LCT)

旧城冷巷雨未停 提交于 2019-11-28 10:08:02

滚回来学文化课了……

题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=2759

题解

LCT,显然的做法是维护链上所有一次函数的复合。
如何处理根的问题?

考虑所有的连通块都建成有根树,另外记录每个根的父亲。
修改父亲的时候,如果修改的是根,那么要么直接改,要么合并两个连通块,根变为非根;如果修改的不是根,要特判分裂了两个连通块导致根的父亲进了新的连通块的情况,如果如此则需重新合并,根变为非根,其余直接改即可。

时间复杂度\(O(n\log n)\).

代码

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cassert>
using namespace std;

void read(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}

const int N = 3e4;
const int P = 1e4+7;
int inv[P+2];
struct Data
{
    int a,b;
    Data() {}
    Data(int _a,int _b) {a = _a,b = _b;}
    Data operator *(const Data &arg) const {return Data(a*arg.a%P,(b*arg.a+arg.b)%P);}
    int calc(int x) {return (a*x+b)%P;}
    int solve()
    {
        if(a==0) {return b==0?-2:-1;}
        return inv[a]*(P-b)%P;
    }
};
int fa[N+3];
int uf[N+3];
int n,q;

int findfa(int u)
{
    int i = u;
    while(u!=uf[u]) {u = uf[u];}
    while(u!=uf[i])
    {
        int j = uf[i]; uf[i] = u; i = j;
    }
    return u;
}

struct SplayNode
{
    int son[2],fa; Data val,sum;
} spl[N+3];
bool isroot(int u) {return spl[spl[u].fa].son[0]!=u && spl[spl[u].fa].son[1]!=u;}
void pushup(int u)
{
    int ls = spl[u].son[0],rs = spl[u].son[1];
    spl[u].sum = spl[u].val;
    if(ls) {spl[u].sum = spl[ls].sum*spl[u].sum;}
    if(rs) {spl[u].sum = spl[u].sum*spl[rs].sum;}
}
void rotate(int u)
{
    int x = spl[u].fa,y = spl[x].fa,dir = u==spl[x].son[0];
    if(!isroot(x)) {spl[y].son[x==spl[y].son[1]] = u;}
    spl[u].fa = y;
    spl[x].son[dir^1] = spl[u].son[dir];
    if(spl[u].son[dir]) {spl[spl[u].son[dir]].fa = x;}
    spl[u].son[dir] = x; spl[x].fa = u;
    pushup(x);
}
void splaynode(int u)
{
    int x = u;
    while(!isroot(x))
    {
        x = spl[x].fa;
    }
    while(!isroot(u))
    {
        int y = spl[u].fa,z = spl[y].fa;
        if(!isroot(y)) {(u==spl[y].son[1])^(y==spl[z].son[1]) ? rotate(u) : rotate(y);}
        rotate(u);
    }
    pushup(u);
}
void access(int u)
{
    for(int i=0; u; i=u,u=spl[u].fa)
    {
        splaynode(u);
        spl[u].son[1] = i;
        pushup(u);
    }
}
int findroot(int u,int flg=0)
{
    access(u); splaynode(u);
    while(spl[u].son[0]) u = spl[u].son[0];
    if(flg) splaynode(u);
    return u;
}
void link(int u,int v) //fa[u]=v
{
//  printf("link %d %d\n",u,v);
    access(u); splaynode(u);
    spl[u].fa = v;
}
void cut(int u) //fa[u]=v
{
//  printf("cut %d\n",u);
    access(u); splaynode(u);
    int v = spl[u].son[0]; spl[u].son[0] = spl[v].fa = 0;
    pushup(u);
}
void modify(int u,Data x)
{
    splaynode(u);
    spl[u].val = x;
}

int main()
{
    inv[1] = 1; for(int i=2; i<P; i++) inv[i] = P-(P/i*inv[P%i]%P);
    scanf("%d",&n);
    for(int i=1; i<=n; i++) uf[i] = i;
    for(int i=1; i<=n; i++)
    {
        int u,x,y; scanf("%d%d%d",&x,&u,&y);
        spl[i].val = spl[i].sum = Data(x,y);
        int uu = findfa(u);
        if(uu==i)
        {
            fa[i] = u;
        }
        else
        {
            link(i,u);
            uf[findfa(i)] = uu;
        }
    }
    scanf("%d",&q);
    while(q--)
    {
        char opt[5]; scanf("%s",opt+1);
        if(opt[1]=='A')
        {
            int u; scanf("%d",&u);
            int rt = findroot(u);
            access(fa[rt]); splaynode(fa[rt]);
            int x = Data((spl[fa[rt]].sum.a-1+P)%P,spl[fa[rt]].sum.b).solve();
            if(x<0) {printf("%d\n",x);}
            else
            {
                access(u); splaynode(u);
                int ans = spl[u].sum.calc(x);
                printf("%d\n",ans);
            }
        }
        else if(opt[1]=='C')
        {
            int u,ax,ay,v; scanf("%d%d%d%d",&u,&ax,&v,&ay);
            modify(u,Data(ax,ay));
            if(fa[u])
            {
                int rtv = findroot(v);
                if(rtv==u) {fa[u] = v;}
                else
                {
                    fa[u] = 0;
                    link(u,v);
                }
            }
            else
            {
                int rt = findroot(u);
                cut(u);
                int rtf = findroot(fa[rt]);
                if(rtf==u)
                {
                    link(rt,fa[rt]);
                    fa[rt] = 0;
                }
                int rtv = findroot(v);
                if(rtv==u) {fa[u] = v;}
                else {link(u,v);}
            }
        }
    }
    return 0;
} 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!