[kuangbin]树链剖分

Aragorn’s Story HDU - 3966

题目链接

https://vjudge.net/problem/HDU-3966

题目思路

模板题

ac代码

const int maxn = 5e4+10;
const int inf = 1e9+10;
const ll llinf =1e18+10;
const ll mod = 1e9+7;
const double pi = acos(-1);


int n,m,p;
vector<int>vec[maxn];
int a[maxn];
char str[10];
int dep[maxn],siz[maxn],f[maxn],son[maxn],top[maxn],pos[maxn],in[maxn],cnt;
int t[maxn<<4],lz[maxn<<4];

void dfs1(int x,int fa)
{
    dep[x]=dep[fa]+1;
    f[x]=fa;
    siz[x]=1;
    int maxsize=-1;
    for(auto to:vec[x])
    {
        if(to==fa)continue;
        dfs1(to,x);
        siz[x]+=siz[to];
        if(siz[to]>maxsize)
        {
            son[x]=to;
            maxsize=siz[to];
        }
    }
}

void dfs2(int x,int t)
{
    in[x]=++cnt;
    pos[cnt]=x;
    top[x]=t;
    if(son[x]==0)return;
    dfs2(son[x],t);
    for(auto to:vec[x])
    {
        if(to==f[x]||to==son[x])continue;
        dfs2(to,to);
    }
}


void pushup(int rt)
{
    t[rt]=t[lson]+t[rson];
}

void pushdown(int rt,int l,int r)
{
    if(lz[rt])
    {
        int mid=(l+r)>>1;
        t[lson]+=lz[rt]*(mid-l+1);
        t[rson]+=lz[rt]*(r-mid);
        lz[lson]+=lz[rt];
        lz[rson]+=lz[rt];
        lz[rt]=0;
    }
}

void build(int rt,int l,int r)
{
    lz[rt]=0;
    if(l==r)
    {
        t[rt]=a[pos[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    pushup(rt);

}

void update(int rt,int l,int r,int L,int R,int k)
{
    if(L<=l&&r<=R)
    {
        t[rt]+=k*(r-l+1);
        lz[rt]+=k;
        return;
    }
    int mid=(l+r)>>1;
    pushdown(rt,l,r);
    if(L<=mid)
        update(lson,l,mid,L,R,k);
    if(R>mid)
        update(rson,mid+1,r,L,R,k);
    pushup(rt);
}

int query(int rt,int l,int r,int L,int R)
{
    if(L<=l&&r<=R)
    {
        return t[rt];
    }
    int mid=(l+r)>>1;
    pushdown(rt,l,r);
    int ans=0;
    if(L<=mid)
        ans+=query(lson,l,mid,L,R);
    if(R>mid)
        ans+=query(rson,mid+1,r,L,R);
    return ans;
}

void updrange(int x,int y,int k)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        update(1,1,n,in[top[x]],in[x],k);
        x=f[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    update(1,1,n,in[x],in[y],k);
}

signed main()
{
    while(~scanf("%d%d%d",&n,&m,&p))
    {
        cnt=0;
        for(int i=1;i<=n;i++)son[i]=0,vec[i].clear();
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1,u,v;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            vec[u].push_back(v);
            vec[v].push_back(u);
        }
        dfs1(1,1);
        dfs2(1,1);
        build(1,1,n);

        while(p--)
        {
            int x,y,z;
            scanf("%s",str);
            if(str[0]=='Q')
            {
                scanf("%d",&x);
                printf("%d\n",query(1,1,n,in[x],in[x]));
            }else
            {
                scanf("%d%d%d",&x,&y,&z);
                if(str[0]=='I')
                    updrange(x,y,z);
                else
                    updrange(x,y,-z);
            }

        }
    }
}



Housewife Wind POJ - 2763

题目链接

https://vjudge.net/problem/POJ-2763

题目思路

将边的值赋给深度大的端点后,就是一个模板题了。
因为我们求得是边的和,并且我们是向下赋值,所以查询的时候要注意不要多算边。

poj好多东西都不能用,做题体验蛮差的(小声bb)

ac代码

const int maxn = 3e5+10;
const int inf = 1e9+10;
const ll llinf =1e18+10;
const ll mod = 1e9+7;


int n,m,s;
int a[maxn];
pii e[maxn];
char str[10];
int dep[maxn],siz[maxn],f[maxn],son[maxn],top[maxn],pos[maxn],in[maxn],cnt,tot;
int t[maxn<<4],lz[maxn<<4];
int first[maxn];

struct node
{
    int to,next,w;
}E[maxn];

void add(int u,int v,int w)
{
    E[++tot].to=v;
    E[tot].next=first[u];
    E[tot].w=w;
    first[u]=tot;
}

void dfs1(int x,int fa)
{
    dep[x]=dep[fa]+1;
    f[x]=fa;
    siz[x]=1;
    int maxsize=-1;
    for(int i=first[x];i;i=E[i].next)
    {
        int to=E[i].to;
        if(to==fa)continue;
        a[to]=E[i].w;
        dfs1(to,x);
        siz[x]+=siz[to];
        if(siz[to]>maxsize)
        {
            son[x]=to;
            maxsize=siz[to];
        }
    }
}

void dfs2(int x,int t)
{
    in[x]=++cnt;
    pos[cnt]=x;
    top[x]=t;
    if(son[x]==0)return;
    dfs2(son[x],t);
     for(int i=first[x];i;i=E[i].next)
    {
        int to=E[i].to;
        if(to==f[x]||to==son[x])continue;
        dfs2(to,to);
    }
}


void pushup(int rt)
{
    t[rt]=t[lson]+t[rson];
}

void pushdown(int rt,int l,int r)
{
    if(lz[rt])
    {
        int mid=(l+r)>>1;
        t[lson]+=lz[rt]*(mid-l+1);
        t[rson]+=lz[rt]*(r-mid);
        lz[lson]+=lz[rt];
        lz[rson]+=lz[rt];
        lz[rt]=0;
    }
}

void build(int rt,int l,int r)
{
    lz[rt]=0;
    if(l==r)
    {
        t[rt]=a[pos[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    pushup(rt);

}

void update(int rt,int l,int r,int L,int R,int k)
{
    if(L<=l&&r<=R)
    {
        t[rt]=k*(r-l+1);
        lz[rt]=k;
        return;
    }
    int mid=(l+r)>>1;
    pushdown(rt,l,r);
    if(L<=mid)
        update(lson,l,mid,L,R,k);
    if(R>mid)
        update(rson,mid+1,r,L,R,k);
    pushup(rt);
}

int query(int rt,int l,int r,int L,int R)
{
    if(L<=l&&r<=R)
    {
        return t[rt];
    }
    int mid=(l+r)>>1;
    pushdown(rt,l,r);
    int ans=0;
    if(L<=mid)
        ans+=query(lson,l,mid,L,R);
    if(R>mid)
        ans+=query(rson,mid+1,r,L,R);
    return ans;
}

int qyrange(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=query(1,1,n,in[top[x]],in[x]);//这里我们后面会直接跳到top[x]的父亲节点,所以不用加一
        x=f[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    ans+=query(1,1,n,in[x]+1,in[y]);//不加一会多计算一条边的权值
    return ans;
}

signed main()
{
    while(~scanf("%d%d%d",&n,&m,&s))
    {
        cnt=0;
        for(int i=1;i<=n;i++)son[i]=0,first[i];
        for(int i=1,u,v,w;i<=n-1;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
            e[i].fi=u,e[i].se=v;
        }
        dfs1(1,1);
        dfs2(1,1);
        build(1,1,n);

        while(m--)
        {
            int x,y,z;
            scanf("%d%d",&x,&y);
            if(x==0)
            {
                printf("%d\n",qyrange(s,y));
                s=y;
            }else
            {
                scanf("%d",&z);
                int l=e[y].fi,r=e[y].se;
                if(dep[l]>dep[r])
                    update(1,1,n,in[l],in[l],z);
                else
                    update(1,1,n,in[r],in[r],z);
            }

        }
    }
}



Tree POJ - 3237

题目链接

https://vjudge.net/problem/POJ-3237

题目思路

查询和修改边的值跟上题写法一样。
主要看取反的操作。
我们对于一组数全部乘上-1,不难发现这组数中最大值会变得最小,最小值会变得最大。
那么我们用线段树维护一个区间的最大值和最小值,每次取反操作把最大值最小值乘上-1后交换最大最小值就好了。
需要注意的是因为有负数,所以查询的时候统计答案的变量不能初始化为0,找了半个多小时的bug。。。

ac代码

const int maxn = 3e5+10;
const int inf = 1e9+10;
const ll llinf =1e18+10;
const ll mod = 1e9+7;


int n,m,s;
int a[maxn];
pii e[maxn];
char str[10];
int dep[maxn],siz[maxn],f[maxn],son[maxn],top[maxn],pos[maxn],in[maxn],cnt,tot;
pii t[maxn<<4];
int lz[maxn<<4];
int first[maxn];

struct node
{
    int to,next,w;
}E[maxn];

void add(int u,int v,int w)
{
    E[++tot].to=v;
    E[tot].next=first[u];
    E[tot].w=w;
    first[u]=tot;
}

void dfs1(int x,int fa)
{
    dep[x]=dep[fa]+1;
    f[x]=fa;
    siz[x]=1;
    int maxsize=-1;
    for(int i=first[x];i;i=E[i].next)
    {
        int to=E[i].to;
        if(to==fa)continue;
        a[to]=E[i].w;
        dfs1(to,x);
        siz[x]+=siz[to];
        if(siz[to]>maxsize)
        {
            son[x]=to;
            maxsize=siz[to];
        }
    }
}

void dfs2(int x,int t)
{
    in[x]=++cnt;
    pos[cnt]=x;
    top[x]=t;
    if(son[x]==0)return;
    dfs2(son[x],t);
     for(int i=first[x];i;i=E[i].next)
    {
        int to=E[i].to;
        if(to==f[x]||to==son[x])continue;
        dfs2(to,to);
    }
}


void pushup(int rt)
{
    t[rt].fi=max(t[lson].fi,t[rson].fi);
    t[rt].se=min(t[lson].se,t[rson].se);
}

void pushdown(int rt)
{
    if(lz[rt]<0)
    {
        t[lson].fi*=lz[rt];
        t[rson].fi*=lz[rt];
        t[lson].se*=lz[rt];
        t[rson].se*=lz[rt];
        swap(t[lson].fi,t[lson].se);
        swap(t[rson].fi,t[rson].se);
        lz[lson]*=lz[rt];
        lz[rson]*=lz[rt];
        lz[rt]=1;
    }
}

void build(int rt,int l,int r)
{
    lz[rt]=1;
    if(l==r)
    {
        t[rt].fi=a[pos[l]];
        t[rt].se=a[pos[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    pushup(rt);

}

void update(int rt,int l,int r,int L,int R,int k)
{
    if(L<=l&&r<=R)
    {
        t[rt].fi*=k;
        t[rt].se*=k;
        swap(t[rt].fi,t[rt].se);
        lz[rt]*=k;
        return;
    }
    int mid=(l+r)>>1;
    pushdown(rt);
    if(L<=mid)
        update(lson,l,mid,L,R,k);
    if(R>mid)
        update(rson,mid+1,r,L,R,k);
    pushup(rt);
}

int query(int rt,int l,int r,int L,int R)
{
    if(L<=l&&r<=R)
    {
        return t[rt].fi;
    }
    int mid=(l+r)>>1;
    pushdown(rt);
    int ans=-inf;
    if(L<=mid)
        ans=max(ans,query(lson,l,mid,L,R));
    if(R>mid)
        ans=max(ans,query(rson,mid+1,r,L,R));
    return ans;
}

int qyrange(int x,int y)
{
    int ans=-inf;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=max(ans,query(1,1,n,in[top[x]],in[x]));
        x=f[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    ans=max(ans,query(1,1,n,in[x]+1,in[y]));
    return ans;
}

void updrange(int x,int y,int k)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        update(1,1,n,in[top[x]],in[x],k);
        x=f[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    update(1,1,n,in[x]+1,in[y],k);
}

void change(int rt,int l,int r,int p,int v)
{
    if(l==r)
    {
        t[rt].fi=v;
        t[rt].se=v;
        return;
    }
    int mid=(l+r)>>1;
    pushdown(rt);
    if(mid>=p)
        change(lson,l,mid,p,v);
    else
        change(rson,mid+1,r,p,v);
    pushup(rt);
}


signed main()
{
    int _;
    scanf("%d",&_);
    while(_--)
    {
        scanf("%d",&n);
        cnt=0,tot=0;
        for(int i=1;i<=n;i++)son[i]=0,first[i]=0;
        for(int i=1,u,v,w;i<=n-1;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
            e[i].fi=u,e[i].se=v;
        }

        dfs1(1,1);
        dfs2(1,1);
        a[1]=-inf;
        build(1,1,n);

        while(scanf("%s",str))
        {
            if(str[0]=='D')break;
            int x,y;
            scanf("%d%d",&x,&y);
            if(str[0]=='Q')
            {
                printf("%d\n",qyrange(x,y));
            }
            if(str[0]=='C')
            {
                int l=e[x].fi,r=e[x].se;
                if(dep[l]<dep[r])swap(l,r);
                change(1,1,n,in[l],y);
            }
            if(str[0]=='N')
            {
                updrange(x,y,-1);
            }
        }
    }
}



Aladdin and the Return Journey LightOJ - 1348

题目链接

https://vjudge.net/problem/LightOJ-1348

题目思路

模板题

Query on a tree SPOJ - QTREE

题目链接

https://vjudge.net/problem/SPOJ-QTREE

题目思路

比POJ - 3237少了取反操作,输入输出都一样,交同一份代码就能过。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值