BZOJ2243

給定一棵有n個節點的無根樹和m個操作,操作有2類:
1、將節點a到節點b路徑上所有點都染成顏色c;
2、詢問節點a到節點b路徑上的顏色段數量(連續相同顏色被認爲是同一段),如“ 112221 ” 由3段組成:“ 11 ” 、“ 222 ” 和“ 1 ” 。
請你寫一個程序依次完成這m個操作。
Input
第一行包含2個整數n和m,分別表示節點數和操作數;
第二行包含n個正整數表示n個節點的初始顏色
下面 行每行包含兩個整數x和y,表示x和y之間有一條無向邊。
下面 行每行描述一個操作:
“C a b c”表示這是一個染色操作,把節點a到節點b路徑上所有點(包括a和b)都染成顏色c;
“Q a b”表示這是一個詢問操作,詢問節點a到節點b(包括a和b)路徑上的顏色段數量。
Output
對於每個詢問操作,輸出一行答案。
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
Hint
數N<=10^5,操作數M<=10^5,所有的顏色C爲整數且在[0, 10^9]之間。

思路:
1,這道題主要是對於線段樹的查詢操作,在查詢的時候,如果被查詢的區間被分成了兩半,那麼我們還需判斷分割點處的顏色是否相同,相同就要減一。
2,其次在重鏈中往上跳的時候還要判斷跳的兩端點(也就是t1以及t1的父節點)的顏色是否一樣。

#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=1e5+9;
int sz[maxn],fa[maxn],tp[maxn],son[maxn],dep[maxn],id[maxn],idx,fx[maxn],color[maxn];
int tag[maxn<<2],sum[maxn<<2],ls[maxn<<2],rs[maxn<<2];
int n,m;
vector<int> mp[maxn];

void dfs1(int u,int f,int d)
{
    son[u]=0,sz[u]=1,fa[u]=f,dep[u]=d;
    for(int i=0; i<mp[u].size(); i++)
    {
        int v=mp[u][i];
        if(v==fa[u]) continue;
        dfs1(v,u,d+1);
        sz[u]+=sz[v];
        if(son[u]==0||sz[son[u]]<sz[v])
            son[u]=v;
    }
}
void dfs2(int u,int tpp)
{
    tp[u]=tpp;
    id[u]=++idx;
    fx[idx]=u;
    if(son[u])dfs2(son[u],tpp);
    for(int i=0; i<mp[u].size(); i++)
    {
        int v=mp[u][i];
        if(v==fa[u]||v==son[u]) continue;
        dfs2(v,v);
    }
}
void pushdown(int rt)
{
    if(tag[rt]!=-1)
    {
        tag[rt<<1]=tag[rt<<1|1]=tag[rt];
        ls[rt<<1]=ls[rt<<1|1]=rs[rt<<1]=rs[rt<<1|1]=tag[rt];
        tag[rt]=-1;
        sum[rt<<1]=sum[rt<<1|1]=1;
    }
}
void pushup(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    if(rs[rt<<1]==ls[rt<<1|1])
        sum[rt]--;
    ls[rt]=ls[rt<<1];//由於我的初始化的方式這裏必須這樣寫
    rs[rt]=rs[rt<<1|1];//否則,對於build以後的建樹是有問題的
}
void build(int l,int r,int rt)
{
    tag[rt]=-1;
    if(l==r)
    {
        ls[rt]=rs[rt]=color[fx[l]];
        sum[rt]=1;
        return;
    }
    int m=l+r>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        tag[rt]=c;
        ls[rt]=rs[rt]=c;
        sum[rt]=1;
        return;
    }
    if(tag[rt]==c) return;
    pushdown(rt);
    int m=l+r>>1;
    if(L<=m) update(L,R,c,lson);
    if(m<R) update(L,R,c,rson);
    pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
    if(L==l&&r==R||tag[rt]!=-1)
        return sum[rt];
    pushdown(rt);
    int m=l+r>>1;
    if(m<L)
        return query(L,R,rson);
    else if(R<=m)
        return query(L,R,lson);
    else
    {
        int ret=query(L,m,lson)+query(m+1,R,rson);
        if(rs[rt<<1]==ls[rt<<1|1]) ret--;//判斷分割點處的顏色分配情況
        return ret;
    }
}
int qp(int p,int l,int r,int rt)//查詢改變後的顏色
{
    if(l==r) return ls[rt];
    int m=l+r>>1;
    pushdown(rt);
    if(p<=m) return qp(p,lson);
    else return qp(p,rson);
}
int qq(int l,int r,int op)
{
    int sum=0;
    int t1=tp[l],t2=tp[r];
    while(t2!=t1)
    {
        if(dep[t1]<dep[t2])
        {
            swap(t1,t2);
            swap(l,r);
        }
        if(op!=-1)
            update(id[t1],id[l],op,1,idx,1);
        else
        {
            sum+=query(id[t1],id[l],1,idx,1);
            if(qp(id[fa[t1]],1,idx,1)==qp(id[t1],1,idx,1)) sum--;//處理跳躍點出的情況,這裏畫圖可知,是不可能跳出去的
        }
        l=fa[t1];
        t1=tp[l];
    }
    if(dep[l]>dep[r]) swap(l,r);
    if(op!=-1)
    {
        update(id[l],id[r],op,1,idx,1);
        return -1;
    }
    else
    {
        sum+=query(id[l],id[r],1,idx,1);
        return sum;
    }
}
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++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        mp[u].push_back(v);
        mp[v].push_back(u);
    }

    dfs1(1,-1,1);
    dfs2(1,1);
    build(1,idx,1);
    while(m--)
    {
        char op[3];
        scanf("%s",op);
        int a,b,c;
        scanf("%d%d",&a,&b);
        if(op[0]=='Q')
        {
            printf("%d\n",qq(a,b,-1));
        }
        else
        {
            scanf("%d",&c);
            qq(a,b,c);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章