bzoj2243

2243: [SDOI2011]染色

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 6753  Solved: 2496
[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

第一轮day1

树链剖分练习。

1.每次查询时记得跳上去时,要把两个端点是否相等计算进去。color[num[fa[top[x]]]]==color[num[top[x]]]记得判断,这里用单点查询即可。

(这里不会出现错误,有人会想:fa[top[x]]会不会跳到了这两个点的路径外?不会,因为当dep[top[x]]<dep[top[x]时交换x,y所以当x已经在最上面的区间时,他就不会动了,只有y会向上跳)

2.每次查询时query(l,mid) query(mid+1,r)时也要判断rc[x*2]==lc[x*2+1](查询时)当且仅当a<=mid<b时要判断;(a,b是要查询的区间),因为如果这两个端点不在查询的区间里,那么也就没有必要判断了。

3.tag要先变成-1,颜色可能为0

4.pushdown是把下面节点的信息修改,不是仅仅修改他的tag。(不清楚)

一组数据:

7 3
1 1 1 1 1 1 1
1 2 1 3
2 4 2 5
3 6 3 7
C 6 3 2
C 4 7 1
Q 6 7

这组数据说明了第二条

 

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 200010
struct edge 
{
    int to,nxt;
}e[N];
int n,m,cnt,k;
int head[N],size[N],rc[N<<2],lc[N<<2],sum[N<<2],tag[N<<2];
int num[N],c[N],fa[N],top[N],son[N],dep[N];
void link(int u,int v)
{
    e[++cnt].nxt=head[u];
    head[u]=cnt;
    e[cnt].to=v;
}
int min(int x,int y)
{
    return x<y?x:y;
}
int max(int x,int y)
{
    return x>y?x:y;
}
void dfs1(int u,int Fa)
{
    int Max=0; size[u]=1;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v!=Fa)
        {
            fa[v]=u;
            dep[v]=dep[u]+1;
            dfs1(v,u);
            if(size[v]>Max)
            {
                son[u]=v;
                Max=size[v];
            }
            size[u]+=size[v];
        }
    }
}
void dfs2(int u,int acs,int Fa)
{
    top[u]=acs; num[u]=++k;
    if(son[u]) dfs2(son[u],acs,u);
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v!=Fa&&v!=son[u]) dfs2(v,v,u);
    }
}
void pushdown(int x)
{
    if(tag[x]!=-1)
    {
        tag[x*2+1]=tag[x*2]=tag[x];
        sum[x*2+1]=sum[x*2]=1;
        lc[x*2+1]=lc[x*2]=rc[x*2+1]=rc[x*2]=tag[x];
        tag[x]=-1;
    }
}
void update(int l,int r,int x,int a,int b,int c)
{
    if(l>b||r<a) return;
    if(l>=a&&r<=b)
    {
        tag[x]=lc[x]=rc[x]=c; 
        sum[x]=1;
        return;
    }
    if(r<=b) rc[x]=c;
    if(l>=a) lc[x]=c;
    pushdown(x);
    update(l,(l+r)/2,x*2,a,b,c);
    update((l+r)/2+1,r,x*2+1,a,b,c);
    sum[x]=sum[x*2]+sum[x*2+1]-(rc[x*2]==lc[x*2+1]);
}
int query(int l,int r,int x,int a,int b)
{
    if(l>b||r<a) return 0;
    if(l>=a&&r<=b) return sum[x];
    pushdown(x);
    int ret=0;
    ret+=query(l,(l+r)/2,x*2,a,b);
    ret+=query((l+r)/2+1,r,x*2+1,a,b);
    if((l+r)/2>=a&&(l+r)/2<b) ret-=(rc[x*2]==lc[x*2+1]);
    return ret;
}
int pquery(int l,int r,int x,int pos)
{
    if(l==r) return tag[x];
    pushdown(x);
    if(pos>(l+r)/2) return pquery((l+r)/2+1,r,x*2+1,pos);
    else return pquery(l,(l+r)/2,x*2,pos);
}
void ask(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        ans+=query(1,n,1,num[top[x]],num[x]);
//        printf("color=%d\n",pquery(1,n,1,num[fa[top[x]]]));
        ans-=(pquery(1,n,1,num[top[x]])==pquery(1,n,1,num[fa[top[x]]]));        
        x=fa[top[x]];
    }
    ans+=query(1,n,1,min(num[x],num[y]),max(num[x],num[y]));
    printf("%d\n",ans);
}
void change(int x,int y,int c)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        update(1,n,1,num[top[x]],num[x],c);
        x=fa[top[x]];
    }
    update(1,n,1,min(num[x],num[y]),max(num[x],num[y]),c);
}
int main()
{
    memset(tag,-1,sizeof(tag));
//    lc[0]=rc[0]=-1;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&c[i]);
    }
    for(int i=1;i<n;i++)
    {
        int u,v; scanf("%d%d",&u,&v);
        link(u,v); link(v,u);
    }
    dfs1(1,0);
    dfs2(1,1,0);
    for(int i=1;i<=n;i++)
    {
        update(1,n,1,num[i],num[i],c[i]);
    }
    while(m--)
    {
        char s[10]; scanf("%s",s);    
        if(s[0]=='Q')
        {
            int x,y; scanf("%d%d",&x,&y);
            ask(x,y);
        }
        if(s[0]=='C')
        {
            int x,y,c; scanf("%d%d%d",&x,&y,&c);
            change(x,y,c);
        }    
    }
    return 0;
} 
View Code

 

posted @ 2017-01-04 21:46  19992147  阅读(324)  评论(0编辑  收藏  举报