【bzoj】2243: [SDOI2011]染色(树链剖分)

2243: [SDOI2011]染色

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 6514  Solved: 2371
[Submit][Status][Discuss]

Description

 

给定一棵有n个节点的无根树和m个操作,操作有2类:

1、将节点a到节点b路径上所有点都染成颜色c;

2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”3段组成:“11”、“222”和“1”

请你写一个程序依次完成这m个操作。

 

Input

第一行包含2个整数n和m,分别表示节点数和操作数;

第二行包含n个正整数表示n个节点的初始颜色

下面 行每行包含两个整数x和y,表示xy之间有一条无向边。

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

“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]之间。

 

Source


注意各种操作时候的边界操作即可,即如果两端接口处颜色相同,答案--。
  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 using namespace std;
  5 inline void read(int& x){
  6     char c=getchar();int p=1,n=0;
  7     while(c<'0'||c>'9'){if(c=='-')p=-1;c=getchar();}
  8     while(c>='0'&&c<='9'){n=n*10+c-'0';c=getchar();}
  9     x=p*n;
 10 }
 11 const int maxn=100000,maxm=maxn*2+10;
 12 #define root 1,n,1
 13 #define ls l,m,o<<1
 14 #define rs m+1,r,o<<1|1
 15 int n,m;
 16 int w[maxn];
 17 struct edge{
 18     int v,next;
 19 }a[maxm];
 20 int h[maxn],tot;
 21 void add_e(int x,int y){
 22     a[tot].v=y;
 23     a[tot].next=h[x];
 24     h[x]=tot++;
 25 }
 26 int sz[maxn],son[maxn],fa[maxn],dep[maxn];
 27 void dfs1(int u){
 28     sz[u]=1;son[u]=0;
 29     for(int i=h[u];~i;i=a[i].next){
 30         int v=a[i].v;
 31         if(v==fa[u])continue;
 32         fa[v]=u;
 33         dep[v]=dep[u]+1;
 34         dfs1(v);
 35         sz[u]+=sz[v];
 36         if(sz[v]>sz[son[u]])son[u]=v;
 37     }
 38 }
 39 int tid[maxn],top[maxn],rank[maxn],dfs_clock;
 40 void dfs2(int u,int anc){
 41     tid[u]=++dfs_clock;top[u]=anc;rank[tid[u]]=u;
 42     if(son[u]){
 43         dfs2(son[u],anc);
 44         for(int i=h[u];~i;i=a[i].next){
 45             int v=a[i].v;
 46             if(v==fa[u]||v==son[u])continue;
 47             dfs2(v,v);
 48         }
 49     }
 50 }
 51 int sum[maxn*4],tag[maxn*4],left[maxn*4],right[maxn*4];
 52 int ql,qr,val;
 53 inline void pushup(int o){
 54     left[o]=left[o<<1];right[o]=right[o<<1|1];
 55     sum[o]=sum[o<<1]+sum[o<<1|1];
 56     if(right[o<<1]==left[o<<1|1])sum[o]--;
 57 }
 58 inline void pushdown(int o,int m){
 59     if(tag[o]==-1||m==1)return;
 60     sum[o<<1]=sum[o<<1|1]=1;
 61     tag[o<<1]=tag[o<<1|1]=left[o<<1]=left[o<<1|1]=right[o<<1]=right[o<<1|1]=tag[o];
 62     tag[o]=-1;
 63 }
 64 void build(int l,int r,int o){
 65     tag[o]=-1;
 66     if(l==r){
 67         sum[o]=1;
 68         left[o]=right[o]=w[rank[l]];
 69         return;
 70     }
 71     int m=(l+r)>>1;
 72     build(ls);build(rs);
 73     pushup(o);
 74 }
 75 void update(int l,int r,int o){
 76     if(ql<=l&&r<=qr){
 77         tag[o]=left[o]=right[o]=val;
 78         sum[o]=1;
 79         return;
 80     }
 81     pushdown(o,r-l+1);
 82     int m=(l+r)>>1;
 83     if(ql<=m)update(ls);
 84     if(qr>m)update(rs);
 85     pushup(o);
 86 }
 87 void change(int x,int y){
 88     while(top[x]!=top[y]){
 89         if(dep[top[x]]<dep[top[y]])
 90             swap(x,y);
 91         ql=tid[top[x]];qr=tid[x];
 92         update(root);
 93         x=fa[top[x]];
 94     }
 95     if(dep[x]>dep[y])
 96         swap(x,y);
 97     ql=tid[x];qr=tid[y];
 98     update(root);
 99 }
100 int query(int l,int r,int o){
101     if(ql<=l&&r<=qr){
102         return sum[o];
103     }
104     pushdown(o,r-l+1);
105     int m=(l+r)/2,ret=0,flag1=0,flag2=0;
106     if(ql<=m)ret+=query(ls),flag1=1;
107     if(qr>m)ret+=query(rs),flag2=1;
108     if(flag1==1&&flag2==1&&left[o<<1|1]==right[o<<1])ret--;
109     return ret;
110 }
111 int getc(int l,int r,int o,int pos){
112     if(l==r){
113         return left[o];
114     }
115     pushdown(o,r-l+1);
116     int m=(l+r)>>1;
117     if(pos<=m)return getc(ls,pos);
118     if(pos>m)return getc(rs,pos);
119 }
120 int ask(int x,int y){
121     int ret=0;
122     while(top[x]!=top[y]){
123         if(dep[top[x]]<dep[top[y]])
124             swap(x,y);
125         ql=tid[top[x]];qr=tid[x];
126         ret+=query(root);
127         int ans1=getc(root,tid[top[x]]);
128         int ans2=getc(root,tid[fa[top[x]]]);
129         if(ans1==ans2)ret--;
130         x=fa[top[x]];
131     }
132     if(dep[x]>dep[y])
133         swap(x,y);
134     ql=tid[x];qr=tid[y];
135     ret+=query(root);
136     return ret;
137 }
138 int main(){
139 //    freopen("2243.in","r",stdin);
140     read(n);read(m);
141     for(int i=1;i<=n;i++)
142         read(w[i]);
143     memset(h,-1,sizeof h);tot=0;
144     for(int i=1;i<=n-1;i++){
145         int x,y;
146         read(x);read(y);
147         add_e(x,y);add_e(y,x);
148     }
149     dfs1(1);dfs_clock=0;dfs2(1,1);
150     build(root);
151     for(int i=1;i<=m;i++){
152         char op[5];
153         scanf("%s",&op);
154         if(op[0]=='C'){
155             int x,y;
156             read(x);read(y);read(val);
157             change(x,y);
158         }else{
159             int x,y;read(x);read(y);
160             printf("%d\n",ask(x,y));
161         }
162     }
163     return 0;
164 }

后记:写完这道题以后,感觉自己对树剖和线段树的理解又深了一点,明天就是NOIp了,希望不要辜负自己这些日子来的努力!!!加油!!

posted @ 2016-11-18 17:01  yohanlong  阅读(156)  评论(0编辑  收藏  举报