bzoj 2243: [SDOI2011]染色

2243: [SDOI2011]染色

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 8465  Solved: 3170
[Submit][Status][Discuss]

Description

給定一棵有n個節點的無根樹和m個操作,操作有2類:

1、將節點a到節點b路徑上所有點都染成顏色c

2、詢問節點a到節點b路徑上的顏色段數量(連續相同顏色被認爲是同一段),如“112221”由3段組成:“11”、“222”和“1”。

請你寫一個程序依次完成這m個操作。

Input

第一行包含2個整數nm,分別表示節點數和操作數;

第二行包含n個正整數表示n個節點的初始顏色

下面 行每行包含兩個整數xy,表示xy之間有一條無向邊。

下面 行每行描述一個操作:

“C a b c”表示這是一個染色操作,把節點a到節點b路徑上所有點(包括ab)都染成顏色c

“Q a b”表示這是一個詢問操作,詢問節點a到節點b(包括ab)路徑上的顏色段數量。

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]之間。

Source



巨難受

終於調A了

調了好久QAQ

還是師兄給力

好久沒寫4000K的代碼了

線段樹的部分其實不難,合併的時候如果左區間的右端點顏色和右區間的左端點顏色相同

那麼ans--(ans=左邊的ans+右邊的ans)

難點在樹鏈剖分部分

我們發現合併的順序和方向對答案是有影響的

所以我們要把u邊的ans和v邊的ans的分開存

然後討論左右問題

發現我們在線段樹裏面得到的區間都是左邊id小的,右邊id大的

而id是dfs序,所以id小的深度一定較小


v這邊也是一樣的

所以我們每次都把新得到的區間放在之前的答案的左邊

而當他們在一條重鏈上時


我們需要將新查詢出的答案的左右端點分別跟ans1,ans2比較

重點還是要理解我們每次查詢得到的區間,都是左端點高,右端點低

剩下的就可以推出來了(感謝師兄QAQ)

#include<cstdio>
#include<cstring>
const int N=1e5+7;
struct node
{
    int l,r;
    int sum,ll,rr;
    int set;
    void clear()
    {
        sum=0,ll=0,rr=0;
    }
}e[N*4];
struct edgt
{
    int to,next;
}s[N*2];    
int cnt,first[N];
int size[N],id[N],dep[N],fa[N];
inline void insert(int u,int v)
{
    s[++cnt]=(edgt){v,first[u]};first[u]=cnt;
    s[++cnt]=(edgt){u,first[v]};first[v]=cnt;
}
#define lson ro<<1
#define rson ro<<1|1
inline void pushup(node &ro,node l,node r)
{
    ro.ll=l.ll;
    ro.rr=r.rr;
    ro.sum=l.sum+r.sum;
    if(l.rr==r.ll)  ro.sum--;
}
void build(int ro,int l,int r)
{
    e[ro].l=l;e[ro].r=r;
    if(l==r)    return;
    int mid=(l+r)>>1;
    build(lson,l,mid);build(rson,mid+1,r);
}
#define lazy e[ro].set
inline void pushdown(int ro)
{
    if(lazy)
    {
        e[lson].ll=e[lson].rr=lazy;
        e[rson].ll=e[rson].rr=lazy;
        e[lson].sum=e[rson].sum=1;
        e[lson].set=lazy;
        e[rson].set=lazy;
        lazy=0;
    }
}
node query(int ro,int l,int r)
{
    if(l<=e[ro].l&&e[ro].r<=r)        return e[ro];
    pushdown(ro);
    int mid=(e[ro].l+e[ro].r)>>1;
    if(r<=mid)   return query(lson,l,r);
    else if(l>mid)   return query(rson,l,r);
    else
    {
        node a=query(lson,l,mid);node b=query(rson,mid+1,r);
        node ans;ans.clear();
        pushup(ans,a,b);
        return ans;
    }
}
void modify(int ro,int l,int r,int k)
{
    if(l<=e[ro].l&&e[ro].r<=r)
    {
        e[ro].ll=e[ro].rr=k;lazy=k;e[ro].sum=1;
        return;
    }
    pushdown(ro);
    int mid=(e[ro].l+e[ro].r)>>1;
    if(l<=mid)   modify(lson,l,r,k);
    if(r>mid)    modify(rson,l,r,k);
    pushup(e[ro],e[lson],e[rson]);
}
void dfs1(int x)
{
    size[x]=1;
    for(int k=first[x];k;k=s[k].next)
    {
        if(s[k].to==fa[x])  continue;
        fa[s[k].to]=x;
        dep[s[k].to]=dep[x]+1;
        dfs1(s[k].to);
        size[x]+=size[s[k].to];
    }
}
int sz;int top[N];
void dfs2(int x,int chain)
{
    int i=0;
    id[x]=++sz;top[x]=chain;
    for(int k=first[x];k;k=s[k].next)
    if(dep[s[k].to]>dep[x]&&size[s[k].to]>size[i])        i=s[k].to;
    if(!i)  return;
    dfs2(i,chain);
    for(int k=first[x];k;k=s[k].next)
    if(dep[s[k].to]>dep[x]&&s[k].to!=i)  dfs2(s[k].to,s[k].to);
}
inline void swap(int &a,int &b)
{
    int tmp=a;a=b;b=tmp;
}
int qsum(int u,int v)
{
    node ans1,ans2,a;ans1.clear(),ans2.clear();//lca左邊和右邊的答案 
    bool tag=1;bool flag1=0,flag2=0;
    while(top[u]!=top[v])
    {
        if(dep[top[u]]<dep[top[v]])  swap(u,v),tag^=1;;
        a=query(1,id[top[u]],id[u]);
        if(tag)
        {
            if(flag1)pushup(ans1,a,ans1);
            else ans1.sum=a.sum,ans1.ll=a.ll,ans1.rr=a.rr,flag1=1;
        }
        else
        {
            if(flag2)pushup(ans2,a,ans2);
            else ans2.sum=a.sum,ans2.ll=a.ll,ans2.rr=a.rr,flag2=1;
        }
        u=fa[top[u]];
    }
    if(id[u]>id[v])  swap(u,v),tag^=1;
    a=query(1,id[u],id[v]);
    int ans=a.sum;
    if(tag){
       if(flag1){
            ans+=ans1.sum;
            if(ans1.ll==a.ll)   ans--;
       }
	   if(flag2){
             ans+=ans2.sum;
            if(ans2.ll==a.rr)   ans--;
       }
    }
    else{
        if(flag1){
            ans+=ans1.sum;
            if(ans1.ll==a.rr)   ans--;
       }
       if(flag2){
             ans+=ans2.sum;
            if(ans2.ll==a.ll)   ans--;
       }
    }
    return ans;
}
void qset(int u,int v,int k)
{
    while(top[u]!=top[v])
    {
        if(dep[top[u]]<dep[top[v]])  swap(u,v);
        modify(1,id[top[u]],id[u],k);
        u=fa[top[u]];
    }
    if(id[u]>id[v])  swap(u,v);
    modify(1,id[u],id[v],k);
}
int vi[N];
void change(int ro,int x)
{
    if(e[ro].l==e[ro].r)
    {
        e[ro].sum=1;e[ro].ll=e[ro].rr=vi[x];return;
    }
    int mid=(e[ro].l+e[ro].r)>>1;
    if(id[x]<=mid)   change(lson,x);
    else change(rson,x);
    pushup(e[ro],e[lson],e[rson]);
}
int main()
{
    int n,m,u,v;
    scanf("%d %d",&n,&m);
    build(1,1,n);
    for(int i=1;i<=n;i++)    scanf("%d",&vi[i]);
    for(int i=1;i<n;i++) scanf("%d %d",&u,&v),insert(u,v);
    dfs1(1);dfs2(1,1);
    for(int i=1;i<=n;i++)    change(1,i);
    char a[2];
    int q;
    for(int i=1;i<=m;i++)
    {
        scanf("%s %d %d",a,&u,&v);
        if(a[0]=='C')   scanf("%d",&q),qset(u,v,q);
        else printf("%d\n",qsum(u,v));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章