SDOI2011 染色

题目大意

给定一棵树,要求支持一条链上的权值修改和查询相同权值的段数(比如 1112211 就是三段)

思路

看到有修改,有树,大概就能直接反应过来是树链剖分了吧(虽然我是专门去找的树链剖分题

把一段的值都改成某一个值和区间加一样,用一个数组记录一下,在查询的时候再下放就可以了

线段树中需要记录当前区间最左边的颜色、最右边的颜色还有总的颜色数量,build的时候如果左右孩子中间那段颜色相同(比如【1112】和【211】)颜色总数就-1

对于一条链查询的时候当然也会出现类似的问题,可能两条链中间的一段颜色相同,因此可以写一个查询单点颜色的函数,每一次判断一下当前链的链首【top】和这个节点的父亲所染的颜色是否相同,如果相同颜色总数也要-1

其他的就完全和模版一样了。

代码

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
#define lch o<<1
#define rch o<<1|1
#define mid ((l+r)>>1)
const int maxn = 100005;

int cl[maxn];
int cnt, front[maxn];
int totc[maxn<<2], lc[maxn<<2], rc[maxn<<2], chc[maxn<<2];
int dep[maxn],f[maxn],siz[maxn],hson[maxn],top[maxn];
int tot, id[maxn], real[maxn];

struct Edge
{
    int v,next;
}e[maxn*2];
int n,m;

void AddEdge(int u,int v)
{
    e[++cnt].v = v;
    e[cnt].next = front[u];
    front[u] = cnt;
}

void pushup(int o)
{
    totc[o] = totc[rch] + totc[lch];
    if(lc[rch] == rc[lch])
        totc[o]--;
    lc[o] = lc[lch];
    rc[o] = rc[rch];
}

void pushdown(int o)
{
    if(chc[o])
    {
        int x = chc[o];
        chc[o] = 0;
        totc[lch] = totc[rch] = 1;
        chc[lch] = chc[rch] = lc[lch] = rc[lch] = lc[rch] = rc[rch] = x;
    }
}

void build(int o,int l,int r)
{
    if(l == r)
    {
        totc[o] = 1;
        lc[o] = rc[o] = cl[real[l]];
        return;
    }
    build(lch,l,mid);
    build(rch,mid+1,r);
    pushup(o);
}

void optchan(int o,int l,int r,int ql,int qr, int c)
{
    if(ql <= l && r <= qr)
    {
        totc[o] = 1;
        lc[o] = rc[o] = chc[o] = c;
        return;
    }
    pushdown(o);
    if(ql <= mid) optchan(lch, l, mid, ql, qr, c);
    if(qr >= mid+1) optchan(rch, mid+1, r, ql, qr, c);
    pushup(o);
}

int querytot(int o,int l,int r,int ql, int qr)
{
    if(ql > r || qr < l) return 0;
    if(ql <= l && r <= qr)
    {
        return totc[o];
    }
    int res = 0;
    pushdown(o);
    if(qr <= mid) 
    {
        querytot(lch,l,mid,ql,qr);
    }
    else if(ql >= mid+1) 
    {
        querytot(rch,mid+1,r,ql,qr);
    }
    else
    {
        res = querytot(lch,l,mid,ql,qr) + querytot(rch,mid+1,r,ql,qr);
        if(rc[lch] == lc[rch]) res--;
        return res;
    }
}

int querycol(int o,int l,int r,int x)
{
    if(l == r)
    {
        return lc[o];
    }
    pushdown(o);
    if(x <= mid) querycol(lch,l,mid,x);
    else querycol(rch,mid+1,r,x);
}

void dfs1(int u)
{
    dep[u] = dep[f[u]]+1;
    siz[u] = 1;
    for (int i = front[u]; i; i = e[i].next)
    {
        if(e[i].v != f[u])
        {
            f[e[i].v] = u;
            dfs1(e[i].v);
            siz[u] += siz[e[i].v];
            if(siz[e[i].v] > siz[hson[u]] || hson[u] == 0)
            {
                hson[u] = e[i].v;
            }
        }
    }
}

void dfs2(int u)
{
    if(!top[u]) top[u] = u;
    id[u] = ++tot;
    real[tot] = u;
    if(hson[u])
    {
        top[hson[u]] = top[u];
        dfs2(hson[u]);
    }
    for (int i = front[u]; i; i = e[i].next)
    {
        if(e[i].v != hson[u] && e[i].v != f[u])
        {
            dfs2(e[i].v);
        }
    }
}

void rcolor()
{
    int a,b,c;
    scanf("%d%d%d",&a,&b,&c);
    while(top[a] != top[b])
    {
        if(dep[top[a]] < dep[top[b]])
        {
            swap(a,b);
        }
        optchan(1,1,n,id[top[a]],id[a],c);
        a = f[top[a]];
    }    
    if(dep[a] < dep[b])
    {
        swap(a,b);
    }
    optchan(1,1,n,id[b],id[a],c);
}

void rquery()
{
    int a,b;
    scanf("%d%d",&a,&b);
    int res = 0;
    int c1,c2;
    while(top[a] != top[b])
    {
        if(dep[top[a]] < dep[top[b]])
        {
            swap(a,b);
        }
        res += querytot(1,1,n,id[top[a]],id[a]);
        c1 = querycol(1,1,n,id[top[a]]);
        c2 = querycol(1,1,n,id[f[top[a]]]);
//        cout<<c1<<" "<<c2<<endl;
        if(c1 == c2) res--;
        a = f[top[a]];
    }    
    if(dep[a] < dep[b])
    {
        swap(a,b);
    }
    res += querytot(1,1,n,id[b],id[a]);
    if(!res) res = 1;
    printf("%d\n",res);
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d",&cl[i]);
    }
    for (int i = 1; i < n; i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        AddEdge(x,y);
        AddEdge(y,x);
    }
    dfs1(1);
    dfs2(1);
    build(1,1,n);
    for (int i = 1; i <= m; i++)
    {
        char op;
        cin>>op;
        if(op == 'C') rcolor();
        else rquery();
    }
    return 0;
}
View Code

 

posted @ 2018-12-08 13:03  ELU_FOREVER  阅读(97)  评论(0)    收藏  举报