bzoj 2243: [SDOI2011]染色

bzoj 2243: [SDOI2011]染色

树链剖分,线段树

题意

给定一棵有n个节点的无根树和m个操作,操作有2类:

  1. 将节点a到节点b路径上所有点都染成颜色c;
  2. 询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。

请你写一个程序依次完成这m个操作。

思路

这种东西。。感觉很套路啊,学会了之后根本不难写,顶多是代码太多写丑了需要调。而且能解决的问题也都很套路。。还是我没碰到高级的问题?

在树上的修改查询,想到树链剖分。我之前一篇Gym的题解说的挺细,不带修改。这题带修改,也没什么区别。修改时也是跟查询一样,往爸爸上跳,直到跳到重链。

啊。。这题,合并查询结果时要注意一下,比如lres有结果,rres没结果,那么返回lres就行,或者合并时把res的右端点给赋值。

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=100007;
const int oo=0x3f3f3f3f;

vector<int> G[MAXN];
int Val[MAXN], Hson[MAXN], SonAmount[MAXN], Father[MAXN], Depth[MAXN];
int Dfsnum[MAXN], TreeValue[MAXN], TopOfHeavyChain[MAXN];
int dfscount;

void AddEdge(int from, int to)
{
    G[from].push_back(to);
    G[to].push_back(from);
}

void dfs1(int n)
{
    SonAmount[n]=1;
    for(int i=0;i<G[n].size();i++)
    {
        int to=G[n][i];
        if(Depth[to]) continue;
        Depth[to]=Depth[n]+1;
        Father[to]=n;
        dfs1(to);
        SonAmount[n]+=SonAmount[to];
        if(SonAmount[to]>SonAmount[Hson[n]]) Hson[n]=to;
    }
    return;
}
void dfs2(int n, int prev)
{
    Dfsnum[n]=++dfscount;
    TreeValue[dfscount]=Val[n];
    TopOfHeavyChain[n]=prev;
    if(!Hson[n]) return;
    dfs2(Hson[n], prev);
    for(int i=0;i<G[n].size();i++)
    {
        int to=G[n][i];
        if(to==Hson[n]||to==Father[n]) continue;
        dfs2(to, to);
    }
}

struct Stree
{
    int block;
    int lcol, rcol;
    int lazy;
    Stree() { block=0;lcol=rcol=lazy=0; }
    Stree operator + (const Stree &b)const 
    {
        Stree res;
        res.lcol=lcol, res.rcol=b.rcol;
        if(rcol==b.lcol) res.block=block+b.block-1;
        else res.block=block+b.block;

        return res;
    }
}stree[MAXN<<2];
void build(int l, int r, int rt)
{
    if(l==r)
    {
        stree[rt].block=1;
        stree[rt].lcol=stree[rt].rcol=TreeValue[l];
        return;
    }
    int mid=(l+r)>>1;
    build(lson), build(rson);
    stree[rt]=stree[rt<<1]+stree[rt<<1|1];
}
void pushdown(int rt)
{
    if(stree[rt].lazy!=0)
    {
        int c=stree[rt].lazy;stree[rt].lazy=0;
        stree[rt<<1].lazy=stree[rt<<1|1].lazy=c;
        stree[rt<<1].block=stree[rt<<1|1].block=1;
        stree[rt<<1].lcol=stree[rt<<1|1].lcol=c;
        stree[rt<<1].rcol=stree[rt<<1|1].rcol=c;
    }
}
void update(int L, int R, int c, int l, int r, int rt)
{
    if(L<=l&&r<=R)
    {
        stree[rt].block=1;
        stree[rt].lazy=c;
        stree[rt].lcol=stree[rt].rcol=c;
        return;
    }
    pushdown(rt);
    int mid=(l+r)>>1;
    if(L<=mid) update(L, R, c, lson);
    if(mid<R) update(L, R, c, rson);
    stree[rt]=stree[rt<<1]+stree[rt<<1|1];
}
Stree query(int L, int R, int l, int r, int rt)
{
    if(L<=l&&r<=R) return stree[rt];
    pushdown(rt);
    int mid=(l+r)>>1;
    bool tl=0, tr=0;
    if(R<=mid) return query(L, R, lson);
    if(mid<L) return query(L, R, rson);
    return query(L, R, lson)+query(L, R, rson);
}
void solvequ(int n)
{
    Stree lc, rc;
    int l, r;scanf("%d%d", &l, &r);
    int fl=TopOfHeavyChain[l], fr=TopOfHeavyChain[r];
    while(fl!=fr)
    {
        if(Depth[fl]>Depth[fr])
        {
            lc=query(Dfsnum[fl], Dfsnum[l], 1, n, 1)+lc;
            l=Father[fl];
            fl=TopOfHeavyChain[l];
        }
        else
        {
            rc=query(Dfsnum[fr], Dfsnum[r], 1, n, 1)+rc;
            r=Father[fr];
            fr=TopOfHeavyChain[r];
        }
    }
    if(Depth[l]>Depth[r])
        lc=query(Dfsnum[r], Dfsnum[l], 1, n, 1)+lc;
    else rc=query(Dfsnum[l], Dfsnum[r], 1, n, 1)+rc;
    swap(lc.lcol, lc.rcol);
    printf("%d\n", (lc+rc).block);
}
void solveup(int n)
{
    int l, r;scanf("%d%d", &l, &r);
    int c;scanf("%d", &c);
    int fl=TopOfHeavyChain[l], fr=TopOfHeavyChain[r];
    while(fl!=fr)
    {
        if(Depth[fl]>Depth[fr])
        {
            update(Dfsnum[fl], Dfsnum[l], c, 1, n, 1);
            l=Father[fl];
            fl=TopOfHeavyChain[l];
        }
        else
        {
            update(Dfsnum[fr], Dfsnum[r], c, 1, n, 1);
            r=Father[fr];
            fr=TopOfHeavyChain[r];
        }
    }
    if(Depth[l]>Depth[r])
        update(Dfsnum[r], Dfsnum[l], c, 1, n, 1);
    else update(Dfsnum[l], Dfsnum[r], c, 1, n, 1);
}
int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("ou1.txt", "w", stdout);
    int n, m;
    while(scanf("%d%d", &n, &m)==2)
    {
        dfscount=0;M(Hson, 0);
        for(int i=1;i<=n;i++) G[i].clear();

        for(int i=1;i<=n;i++) scanf("%d", &Val[i]);
        for(int i=1;i<n;i++)
        {
            int ta, tb;scanf("%d%d", &ta, &tb);
            AddEdge(ta, tb);
        }

        Depth[1]=1;dfs1(1);dfs2(1, 1);
        build(1, n, 1);

        while(m--)
        {
            char s[10];scanf("%s", s);
            if(s[0]=='C') solveup(n);
            else solvequ(n);
        }
    }
    //system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值