生活随笔
收集整理的這篇文章主要介紹了
P2486 [SDOI2011]染色(树链剖分+线段树)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
題干描述
輸入描述
輸出格式
對于每個詢問操作,輸出一行答案。
輸入輸出樣例
輸入 #1 復(fù)制
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
輸出 #1 復(fù)制
3
1
2
說明/提示
題干很清楚,就是樹鏈剖分+線段樹的基本操作。但是在實現(xiàn)的過程中有幾個點需要注意一下。
我們分類討論一下:
第一種情況:
左區(qū)間:1231(顏色個數(shù)為4) 右區(qū)間:222(個數(shù)為1)
合并后:1231222(顏色個數(shù)為4+1=5)
這是第一種情況:沒有重復(fù)。
我們再來看第二種:
左區(qū)間:1231(顏色個數(shù)為4)右區(qū)間:121(個數(shù)為3)
合并后:1231121(顏色個數(shù)為4+3-1)
這就是第二種情況了,左區(qū)間的最后一個顏色和右區(qū)間的第一個顏色重合,也就重復(fù)了,所以總數(shù)減一。
因此我們在線段樹更新過程中需要維護這段區(qū)間內(nèi)的最左邊的顏色和最右邊的顏色。如果左兒子的右端點顏色和右兒子的左端點顏色相等的話,就減一就可以了。線段樹區(qū)間合并的操作。
剩下的就是樹鏈剖分將樹剖成幾條鏈了。樹鏈剖分的基本操作。
但是樹鏈剖分之后的這一條鏈上的點并不是通過一次操作就能求出來的,而是經(jīng)過好幾次操作,那么這幾次操作之間相鄰的顏色要是重了,就出現(xiàn)的計數(shù)錯誤。所以我們在求完一次之后,我們需要查詢一下這次左端點的顏色和下一次查詢中右端點的顏色是否相同,如果相同,就減一。
代碼如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std
;const int maxx
=1e5+100;
struct node
{int l
;int r
;int lazy
;int lcor
;int rcor
;int num
;
}p
[maxx
<<2];
struct edge
{int to
,next
;
}e
[maxx
<<1];
int head
[maxx
<<1],top
[maxx
],fa
[maxx
];
int in
[maxx
],son
[maxx
],pre
[maxx
];
int a
[maxx
],deep
[maxx
],size
[maxx
];
int n
,m
,tot
,sign
;
inline void init()
{memset(son
,0,sizeof(son
));memset(head
,-1,sizeof(head
));tot
=sign
=0;
}
inline void add(int u
,int v
)
{e
[tot
].to
=v
,e
[tot
].next
=head
[u
],head
[u
]=tot
++;
}
inline void dfs1(int u
,int f
)
{fa
[u
]=f
;deep
[u
]=deep
[f
]+1;size
[u
]=1;for(int i
=head
[u
];i
!=-1;i
=e
[i
].next
){int to
=e
[i
].to
;if(to
==f
) continue;dfs1(to
,u
);size
[u
]+=size
[to
];if(size
[to
]>size
[son
[u
]]) son
[u
]=to
;}
}
inline void dfs2(int u
,int Top
)
{in
[u
]=++sign
;pre
[sign
]=u
;top
[u
]=Top
;if(son
[u
]) dfs2(son
[u
],Top
);for(int i
=head
[u
];i
!=-1;i
=e
[i
].next
){int to
=e
[i
].to
;if(to
==fa
[u
]||to
==son
[u
]) continue;dfs2(to
,to
);}
}
inline void pushup(int cur
)
{p
[cur
].lcor
=p
[cur
<<1].lcor
;p
[cur
].rcor
=p
[cur
<<1|1].rcor
;p
[cur
].num
=p
[cur
<<1].num
+p
[cur
<<1|1].num
;if(p
[cur
<<1].rcor
==p
[cur
<<1|1].lcor
) p
[cur
].num
--;
}
inline void pushdown(int cur
)
{if(p
[cur
].lazy
!=-1){p
[cur
<<1].lazy
=p
[cur
<<1|1].lazy
=p
[cur
].lazy
;p
[cur
<<1].lcor
=p
[cur
<<1].rcor
=p
[cur
<<1|1].lcor
=p
[cur
<<1|1].rcor
=p
[cur
].lcor
;p
[cur
<<1].num
=p
[cur
<<1|1].num
=1;p
[cur
].lazy
=-1;}
}
inline void build(int l
,int r
,int cur
)
{p
[cur
].l
=l
;p
[cur
].r
=r
;p
[cur
].num
=0;p
[cur
].lazy
=-1;p
[cur
].lcor
=p
[cur
].rcor
=-1;if(l
==r
) {p
[cur
].lcor
=p
[cur
].rcor
=a
[pre
[l
]];p
[cur
].num
=1;return ;}int mid
=l
+r
>>1;build(l
,mid
,cur
<<1);build(mid
+1,r
,cur
<<1|1);pushup(cur
);
}
inline void update(int l
,int r
,int cur
,int col
)
{int L
=p
[cur
].l
;int R
=p
[cur
].r
;if(l
<=L
&&R
<=r
){p
[cur
].lcor
=p
[cur
].rcor
=col
;p
[cur
].num
=1;p
[cur
].lazy
=col
;return ;}pushdown(cur
);int mid
=L
+R
>>1;if(r
<=mid
) update(l
,r
,cur
<<1,col
);else if(l
>mid
) update(l
,r
,cur
<<1|1,col
);else update(l
,mid
,cur
<<1,col
),update(mid
+1,r
,cur
<<1|1,col
);pushup(cur
);
}
inline node
query(int l
,int r
,int cur
)
{int L
=p
[cur
].l
;int R
=p
[cur
].r
;if(l
<=L
&&R
<=r
) return p
[cur
];pushdown(cur
);int mid
=L
+R
>>1;if(r
<=mid
) return query(l
,r
,cur
<<1);else if(l
>mid
) return query(l
,r
,cur
<<1|1);else{node a
=query(l
,mid
,cur
<<1);node b
=query(mid
+1,r
,cur
<<1|1);node c
;c
.lcor
=a
.lcor
;c
.rcor
=b
.rcor
;c
.num
=a
.num
+b
.num
;if(a
.rcor
==b
.lcor
) c
.num
--;return c
;}
}
inline int query_col(int pos
,int cur
)
{int L
=p
[cur
].l
;int R
=p
[cur
].r
;if(L
==R
) return p
[cur
].lcor
;pushdown(cur
);int mid
=L
+R
>>1;if(pos
<=mid
) return query_col(pos
,cur
<<1);else return query_col(pos
,cur
<<1|1);
}
inline void Update(int x
,int y
,int col
)
{while(top
[x
]!=top
[y
]){if(deep
[top
[x
]]<deep
[top
[y
]]) swap(x
,y
);update(in
[top
[x
]],in
[x
],1,col
);x
=fa
[top
[x
]];}if(deep
[x
]>deep
[y
]) swap(x
,y
);update(in
[x
],in
[y
],1,col
);
}
inline int Query(int x
,int y
)
{int ans
=0;while(top
[x
]!=top
[y
]){if(deep
[top
[x
]]<deep
[top
[y
]]) swap(x
,y
);ans
+=query(in
[top
[x
]],in
[x
],1).num
;int scol
=query_col(in
[top
[x
]],1);int fcol
=query_col(in
[fa
[top
[x
]]],1);if(scol
==fcol
) ans
--;x
=fa
[top
[x
]];}if(deep
[x
]>deep
[y
]) swap(x
,y
);ans
+=query(in
[x
],in
[y
],1).num
;return ans
;
}
int main()
{int x
,y
,z
;char c
[2];scanf("%d%d",&n
,&m
); init();for(int i
=1;i
<=n
;i
++) scanf("%d",&a
[i
]);for(int i
=1;i
<n
;i
++){scanf("%d%d",&x
,&y
);add(x
,y
),add(y
,x
);}deep
[0]=0;dfs1(1,0);dfs2(1,1);build(1,n
,1);while(m
--){scanf("%s",c
);if(c
[0]=='Q') scanf("%d%d",&x
,&y
),printf("%d\n",Query(x
,y
));else {scanf("%d%d%d",&x
,&y
,&z
);Update(x
,y
,z
);}}return 0;
}
簡化到線段版本,就簡單多了。
#include<bits/stdc++.h>
#define ll long long
using namespace std
;const int maxx
=5e5+100;
struct node
{int l
;int r
;int lcol
;int rcol
;int num
;int lazy
;
}p
[maxx
<<2];
int n
,m
;inline void pushdown(int cur
)
{if(p
[cur
].lazy
!=-1){p
[cur
<<1].lcol
=p
[cur
<<1|1].lcol
=p
[cur
<<1].rcol
=p
[cur
<<1|1].rcol
=p
[cur
].lazy
;p
[cur
<<1].num
=p
[cur
<<1|1].num
=1;p
[cur
<<1].lazy
=p
[cur
<<1|1].lazy
=p
[cur
].lazy
;p
[cur
].lazy
=-1;}
}
inline void pushup(int cur
)
{p
[cur
].lcol
=p
[cur
<<1].lcol
;p
[cur
].rcol
=p
[cur
<<1|1].rcol
;p
[cur
].num
=p
[cur
<<1].num
+p
[cur
<<1|1].num
;if(p
[cur
<<1].rcol
==p
[cur
<<1|1].lcol
) p
[cur
].num
--;
}
inline void build(int l
,int r
,int cur
)
{p
[cur
].l
=l
;p
[cur
].r
=r
;p
[cur
].num
=0;p
[cur
].lazy
=-1;if(l
==r
){scanf("%d",&p
[cur
].lcol
);p
[cur
].rcol
=p
[cur
].lcol
;p
[cur
].num
=1;return ;}int mid
=l
+r
>>1;build(l
,mid
,cur
<<1);build(mid
+1,r
,cur
<<1|1);pushup(cur
);
}
inline void update(int l
,int r
,int cur
,int col
)
{int L
=p
[cur
].l
;int R
=p
[cur
].r
;if(l
<=L
&&R
<=r
){p
[cur
].lcol
=p
[cur
].rcol
=col
;p
[cur
].num
=1;p
[cur
].lazy
=col
;return ;}pushdown(cur
);int mid
=L
+R
>>1;if(r
<=mid
) update(l
,r
,cur
<<1,col
);else if(l
>mid
) update(l
,r
,cur
<<1|1,col
);else update(l
,mid
,cur
<<1,col
),update(mid
+1,r
,cur
<<1|1,col
);pushup(cur
);
}
inline node
query(int l
,int r
,int cur
)
{int L
=p
[cur
].l
;int R
=p
[cur
].r
;if(l
<=L
&&R
<=r
) return p
[cur
];pushdown(cur
);int mid
=L
+R
>>1;if(r
<=mid
) return query(l
,r
,cur
<<1);else if(l
>mid
) return query(l
,r
,cur
<<1|1);else {node c
;node a
=query(l
,mid
,cur
<<1);node b
=query(mid
+1,r
,cur
<<1|1);if(a
.rcol
==b
.lcol
) c
.num
=a
.num
+b
.num
-1;else c
.num
=a
.num
+b
.num
;c
.lcol
=a
.lcol
;c
.rcol
=b
.rcol
;return c
;}
}
int main()
{int op
,x
,y
,c
;while(~scanf("%d%d",&n
,&m
)){build(1,n
,1);while(m
--){scanf("%d",&op
);if(op
==1) scanf("%d%d%d",&x
,&y
,&c
),update(x
,y
,1,c
);else{scanf("%d%d",&x
,&y
);if(x
>y
) swap(x
,y
);printf("%d\n",query(x
,y
,1).num
);}}}return 0;
}
努力加油a啊,(o)/~
總結(jié)
以上是生活随笔為你收集整理的P2486 [SDOI2011]染色(树链剖分+线段树)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。