codevs1566 染色 省队选拔赛山东 SDOI2011DAY1[五星]

题目链接? ——————————————>这里———–>还有这里

题目描述 Description

给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。

输入描述 Input Description

第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面n-1行每行包含两个整数 和 ,表示x和y之间有一条无向边。
下面m行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

输出描述 Output Description

对于每个询问操作,输出一行答案。
样例输入 Sample Input
6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5

样例输出 Sample Output

3
1
2

数据范围

边10W,点1W

题解

链剖练习题了……
这题如果不是树而是区间,就是个线段树傻逼题,然而这题弄到了树上,既然线段树能做,还是在树上操作,就想到了链剖……

对于每个线段树节点记录,左儿子,右儿子,左端点颜色,右端点颜色,区间答案,以及flag,即

struct Tree{
    int l,r,lc,rc,ans,flagc;//lc左端rc右端 颜色 flagc标记 
}tree[size];

这样对于两个子区间:要不就是在区间相接的地方颜色相同,这种情况下,当前区间等于子区间色块和-1,;反之,答案等于子区间色块和~,如下图所示:

11122111

两个2是分属顶层的左儿子和右儿子,如果不加特判,那答案就变成了4,实际答案为3.

然后剩下的就是正常的线段树操作:change,ask,build,update,spread等,详见下面代码
这题恶心的地方在于,需要注意的地方特别多,第一个地方就是刚才说的那个地方,第二个就是在ask时:

if(l <= mid && mid < r && tree[lson].rc == tree[rson].lc)   ans --;

这里的意思和上面一样,也是判断连续区间的部分;
第三个地方是在链剖查询部分,查询区间sum的时候:

if(getcolor(1,w[top[x]]) == getcolor(1,w[fa[top[x]]]))  ans --;

这句话的意思是当前链的顶点与当前链顶点的父亲颜色是否相同,相同ans–;原因还是连续区间的问题,线段树能快速查询区间,但是如果有一种性质可以跨区间,就必须进行特判!

于是这题的思路就这么出来了~:
链剖,然后线段树处理链剖序列,跟一般链剖题一样,就是多加了点特判。

这题我调了半天的RE原因是………………是我读了n条边然而只有n-1条!!!!我这么做居然能A13个点……这数据我真是…………我只想说WTF。
链剖不好调,建议多打,多打,熟练,在第二次打的时候保证必须1a,这样考试的时候你才有可能调出来,因为考试紧张也可能GG了,所以熟练熟练,是最重要的,比你多做几个题甚至要重要23333~

下面附上我的代码~

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<deque>
#include<algorithm>
#define lson p<<1
#define rson p<<1|1
using namespace std;
const int size = 1000010;
const int INF = 2 << 28;
//add edge
int eto[size],head[size],next[size],tot;
void build(int f,int t)
{
    eto[++tot] = t;
    next[tot] = head[f];
    head[f] = tot;
}
//tree pou
int fa[size],son[size],top[size],deep[size],siz[size],w[size];
int dfs_clock,pre[size];
void dfs(int u,int faa,int d)
{
    fa[u] = faa,son[u] = 0,siz[u] = 1,deep[u] = d;
    for(int i = head[u];i;i = next[i])
    {
        int v = eto[i];
        if(v == faa)    continue;
        dfs(v,u,d+1);
        siz[u] += siz[v];
        if(siz[v] > siz[son[u]])    son[u] = v;
    }
}
void dfs2(int u,int faa)
{
    w[u] = ++dfs_clock; top[u] = faa;
    pre[w[u]] = u;
    if(son[u])  dfs2(son[u],faa);
    for(int i = head[u];i;i = next[i])
    {
        int v = eto[i];
        if(v != fa[u] && v != son[u])   dfs2(v,v);
    }
}
//xd tree
int n,m;
struct Tree{
    int l,r,lc,rc,ans,flagc;//lc左端rc右端 颜色 flagc标记 
}tree[size];
int color[size];
void update(int p)
{
    tree[p].lc = tree[lson].lc;
    tree[p].rc = tree[rson].rc;
    if(tree[lson].rc == tree[rson].lc)  tree[p].ans = tree[lson].ans + tree[rson].ans - 1;
    else    tree[p].ans = tree[lson].ans + tree[rson].ans;
}

void build(int p,int l,int r)
{
    tree[p].l = l,tree[p].r = r;
    if(l == r)
    {
        tree[p].lc = tree[p].rc = tree[p].flagc = color[pre[l]];///
        tree[p].ans = 1;
        return ;
    }
    int mid = (l + r) >> 1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    update(p);
}
void spread(int p)
{
    if(tree[p].flagc)
    {
        tree[lson].lc = tree[lson].rc = tree[lson].flagc = tree[p].flagc;
        tree[rson].lc = tree[rson].rc = tree[rson].flagc = tree[p].flagc;
        tree[lson].ans = tree[rson].ans = 1;
        tree[p].flagc = 0;
    }
}
void change(int p,int l,int r,int c)
{
    if(l <= tree[p].l && tree[p].r <= r)
    {
        tree[p].lc = tree[p].rc = tree[p].flagc = c;
        tree[p].ans = 1;
        return ;
    }
    spread(p);
    int mid = (tree[p].l + tree[p].r) >> 1;
    if(l <= mid)    change(lson,l,r,c);
    if(mid < r)     change(rson,l,r,c);
    update(p);
}
int ask(int p,int l,int r)
{
    if(l <= tree[p].l && tree[p].r <= r)    return tree[p].ans;
    spread(p);
    int ans = 0;
    int mid = (tree[p].l + tree[p].r) >> 1;
    if(l <= mid) ans += ask(lson,l,r);
    if(mid < r) ans += ask(rson,l,r);
    if(l <= mid && mid < r && tree[lson].rc == tree[rson].lc)   ans --;
    return ans;
}
void getchange(int x,int y,int c)
{
    while(top[x] != top[y])
    {
        if(deep[top[x]] < deep[top[y]]) swap(x,y);
        change(1,w[top[x]],w[x],c);
        x = fa[top[x]];
    }
    if(deep[x] > deep[y])   swap(x,y);
    change(1,w[x],w[y],c);
}
int getcolor(int p,int id)
{
    if(tree[p].l == tree[p].r)  return tree[p].lc;
    spread(p);
    int mid = (tree[p].l + tree[p].r) >> 1;
    if(id <= mid)   return getcolor(lson,id);
    else    return getcolor(rson,id);
}
int ask_ans(int x,int y)
{
    int ans = 0;
    while(top[x] != top[y])
    {
        if(deep[top[x]] < deep[top[y]]) swap(x,y);
        ans += ask(1,w[top[x]],w[x]);
        if(getcolor(1,w[top[x]]) == getcolor(1,w[fa[top[x]]]))  ans --;
        x = fa[top[x]];
    }
    if(deep[x] > deep[y])   swap(x,y);
    ans += ask(1,w[x],w[y]);
    return ans;
}
char c;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i ++)  scanf("%d",&color[i]);
    for(int i = 1;i < n;i ++)   /WTF!
    {
        int a,b;
        scanf("%d%d",&a,&b);
        build(a,b);
        build(b,a);
    }
    dfs(1,1,1);
    dfs2(1,1);
    build(1,1,n);
    while(m --)
    {
        cin>>c;
        if(c == 'C')
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            getchange(a,b,c);
        }
        else
        {
            int a,b;
            scanf("%d%d",&a,&b);
            printf("%d\n",ask_ans(a,b));
        }
    }
    return 0;
}

-END-




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值