jzoj5783. 【省选模拟2018.8.8】树

题目描述

这里写图片描述

16~83%

不会

100%

用LCT维护树的形态,access后往上跳来找lca
之后用dfs序+线段树维护权值和

其实正解就是直接用lca随便搞搞

话说我已经变成无(sha)脑(bi)数据结构选手了吗。。。

code

#include <iostream>
#include <cstdlib>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define N 300000
using namespace std;

int fa[N+1];
int ch[N+1][2];
bool rev[N+1];
bool isroot[N+1];
long long tr[4*N+1][2];
int a[N+N+1][2];
int ls[N+1];
int w[N+1];
int st[N+1];
int ed[N+1];
int n,Q,i,j,k,l,type,len,root;
long long Find,x,y,z,ans,p;

void New(int x,int y)
{
    len++;
    a[len][0]=y;
    a[len][1]=ls[x];
    ls[x]=len;
}

void swap(int &x,int &y)
{
    int z=x;
    x=y;
    y=z;
}

void init(int fa,int t)
{
    int i;

    st[t]=++j;

    for (i=ls[t]; i; i=a[i][1])
    if (a[i][0]!=fa)
    init(t,a[i][0]);

    ed[t]=j;
}

void down(int t)
{
    if (rev[t])
    {
        swap(ch[t][0],ch[t][1]);

        rev[ch[t][0]]^=1;
        rev[ch[t][1]]^=1;

        rev[t]=0;
    }
}

void rot(int t)
{
    if (isroot[t]) return;

    int Fa=fa[t];
    int x=(ch[Fa][1]==t);

    ch[Fa][x]=ch[t][x^1];
    fa[ch[t][x^1]]=Fa;

    ch[t][x^1]=Fa;
    fa[t]=fa[Fa];
    fa[Fa]=t;

    isroot[t]=isroot[Fa];
    isroot[Fa]=0;

    if (!isroot[t])
    ch[fa[t]][ch[fa[t]][1]==Fa]=t;
}

void splay(int t)
{
    while (!isroot[t])
    {
        down(fa[fa[t]]);
        down(fa[t]);
        down(t);

        if (isroot[fa[t]])
        rot(t);
        else
        if ((ch[fa[fa[t]]][1]==fa[t]) ^ (ch[fa[t]][1]==t))
        rot(t),rot(t);
        else
        rot(fa[t]),rot(t);
    }
}

void access(int t)
{
    int x=0;

    while (t)
    {
        splay(t);
        down(t);

        isroot[ch[t][1]]=1;
        isroot[x]=0;
        ch[t][1]=x;

        x=t;
        t=fa[t];
    }
}

void moveroot(int t)
{
    access(t);
    splay(t);
    root=t;

    rev[t]=1;
    down(t);
}

void link(int x,int y)
{
    moveroot(y);
    fa[y]=x;
}

void Down(int t,int len)
{
    tr[t][0]+=tr[t][1]*len;

    if (len>1)
    {
        tr[t*2][1]+=tr[t][1];
        tr[t*2+1][1]+=tr[t][1];
    }

    tr[t][1]=0;
}

void change(int t,int l,int r,int x,int y,int s)
{
    int mid=(l+r)/2;

    if (x<=l && r<=y)
    {
        tr[t][1]+=s;
        Down(t,r-l+1);

        return;
    }

    Down(t,r-l+1);

    if (x<=mid)
    change(t*2,l,mid,x,y,s);
    if (mid<y)
    change(t*2+1,mid+1,r,x,y,s);

    Down(t*2,mid-l+1);
    Down(t*2+1,r-mid);

    tr[t][0]=tr[t*2][0]+tr[t*2+1][0];
}

void find(int t,int l,int r,int x,int y)
{
    int mid=(l+r)/2;

    Down(t,r-l+1);

    if (x<=l && r<=y)
    {
        Find+=tr[t][0];
        return;
    }

    if (x<=mid)
    find(t*2,l,mid,x,y);
    if (mid<y)
    find(t*2+1,mid+1,r,x,y);
}

bool pd(int x,int y) {return ((st[x]<=st[y]) && (ed[y]<=ed[x]));}

int main()
{
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);

    scanf("%d%d",&n,&Q);
    fo(i,1,n)
    {
        scanf("%d",&w[i]);
        isroot[i]=1;
    }

    fo(i,2,n)
    {
        scanf("%d%d",&x,&y);
        link(x,y);

        New(x,y);
        New(y,x);
    }

    j=0;
    init(0,1);

    fo(i,1,n)
    change(1,1,n,st[i],st[i],w[i]);

    moveroot(1);
    for (;Q;Q--)
    {
        scanf("%d",&type);

        switch (type)
        {
            case 1:
                {
                    scanf("%lld",&x);
                    moveroot(x);

                    break;
                }

            case 2:
                {
                    scanf("%lld%lld%lld",&x,&y,&z);
                    access(x);

                    i=y;
                    while (i)
                    {
                        p=i;
                        while (!isroot[i])
                        i=fa[i];
                        i=fa[i];
                    }

                    if (p==root)
                    {
                        tr[1][1]+=z;
                        Down(1,n);
                    }
                    else
                    if (pd(p,root))
                    {
                        int P=p;

                        tr[1][1]+=z;
                        Down(1,n);

                        access(p);

                        if (!ch[p][0] && !ch[p][1])
                        p=fa[p];
                        else
                        {
                            if (ch[p][0])
                            i=0; else i=1;

                            p=ch[p][i];
                            down(p);//考试时没加上这个
                            i^=1;
                            while (ch[p][i])
                            {
                                p=ch[p][i];
                                down(p);//考试时没加上这个
                            }
                        }

                        change(1,1,n,st[p],ed[p],-z);
                    }
                    else
                    change(1,1,n,st[p],ed[p],z);

                    break;
                }

            case 3:
                {
                    moveroot(root);

                    ans=0;
                    scanf("%lld",&p);

                    if (p==root)
                    {
                        Down(1,n);
                        ans=tr[1][0];
                    }
                    else
                    if (pd(p,root))
                    {
                        Down(1,n);
                        ans=tr[1][0];

                        access(p);

                        if (!ch[p][0] && !ch[p][1])
                        p=fa[p];
                        else
                        {
                            if (ch[p][0])
                            i=0; else i=1;

                            p=ch[p][i];
                            down(p);//考试时没加上这个
                            i^=1;
                            while (ch[p][i])
                            {
                                p=ch[p][i];
                                down(p);//考试时没加上这个
                            }
                        }

                        Find=0;
                        find(1,1,n,st[p],ed[p]);
                        ans-=Find;
                    }
                    else
                    {
                        Find=0;
                        find(1,1,n,st[p],ed[p]);
                        ans=Find;
                    }

                    printf("%lld\n",ans);

                    break;
                }
        }
    }

    fclose(stdin);
    fclose(stdout);

    return 0;
}

后记

考试时因为没下传标记爆掉。。。

这里写图片描述
没错这是同一个程序
O2真神(sha)奇(bi)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值