2243: [SDOI2011]染色
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 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,表示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
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
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 ",ask(x,y)); 161 } 162 } 163 return 0; 164 }
后记:写完这道题以后,感觉自己对树剖和线段树的理解又深了一点,明天就是NOIp了,希望不要辜负自己这些日子来的努力!!!加油!!