# BZOJ 2243 树链剖分

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stdio.h>
#include<queue>
#include<vector>
#include<stack>
#include<map>
#include<set>
#include<time.h>
#include<cmath>
#include<sstream>
#include<assert.h>
using namespace std;
#define L(x) x<<1
#define R(x) x<<1|1
typedef long long int LL;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;
const int MAXN = 1e5 + 10;
struct Edge{
int to, next;
}Edges[MAXN * 2];
Edges[tot].to = v;
}
int id[MAXN], son[MAXN], deep[MAXN], size[MAXN], fa[MAXN], reid[MAXN], top[MAXN];
void Init(){
tot = 0; cnt = 0;
memset(son, -1, sizeof(son));
}
void DFS1(int u, int p,int dep){
fa[u] = p; size[u] = 1; deep[u] = dep;
for (int i = head[u]; i != -1; i = Edges[i].next){
if (Edges[i].to != p){
DFS1(Edges[i].to, u,dep+1);
size[u] += size[Edges[i].to];
if (son[u] == -1 || size[Edges[i].to] > size[son[u]]){
son[u] = Edges[i].to;
}
}
}
}
void DFS2(int u, int tp){
id[u] = ++cnt; reid[id[u]] = u; top[u] = tp;
if (son[u] == -1){ return; }
DFS2(son[u], tp);
for (int i = head[u]; i != -1; i = Edges[i].next){
if (son[u] != Edges[i].to&&Edges[i].to != fa[u]){
DFS2(Edges[i].to, Edges[i].to);
}
}
}
struct Node{
int st, ed;
int lazy,val, lcolor,rcolor;
//懒惰标记，颜色段数，区间左右端点的颜色
}Seg[MAXN * 4];
void pushUp(int k){
Seg[k].lcolor = Seg[L(k)].lcolor;
Seg[k].rcolor = Seg[R(k)].rcolor;
Seg[k].val = Seg[L(k)].val + Seg[R(k)].val;
if (Seg[L(k)].rcolor == Seg[R(k)].lcolor){
Seg[k].val--;
}
}
void pushDown(int k){
//颜色可能等于0
if (Seg[k].lazy!=-1){
Seg[L(k)].val = 1;
Seg[L(k)].lcolor = Seg[L(k)].rcolor = Seg[L(k)].lazy = Seg[k].lazy;
Seg[R(k)].val = 1;
Seg[R(k)].lcolor = Seg[R(k)].rcolor = Seg[R(k)].lazy = Seg[k].lazy;
Seg[k].lazy = -1;
}
}
void Build(int l, int r, int k){
Seg[k].st = l; Seg[k].ed = r;  Seg[k].lazy = -1;
if (l == r){
Seg[k].val = 1;
Seg[k].lcolor = Seg[k].rcolor = value[reid[l]];
return;
}
int mid = (l + r) / 2;
Build(l, mid, L(k)); Build(mid + 1, r, R(k));
pushUp(k);
}
void Modify(int l,int r,int val,int k){
if (Seg[k].st == l&&Seg[k].ed == r){
Seg[k].lazy = Seg[k].lcolor = Seg[k].rcolor = val;
Seg[k].val = 1;
return;
}
pushDown(k);
if (r <= Seg[L(k)].ed){
Modify(l, r, val, L(k));
}
else if (l >= Seg[R(k)].st){
Modify(l, r, val, R(k));
}
else{
Modify(l, Seg[L(k)].ed, val, L(k));
Modify(Seg[R(k)].st, r, val, R(k));
}
pushUp(k);
}
void Modify(int u, int v,int val){
int f1 = top[u], f2 = top[v];
while (f1 != f2){
if (deep[f1] < deep[f2]){
swap(f1, f2);
swap(u, v);
}
Modify(id[f1], id[u], val,1);
u = fa[f1]; f1 = top[u];
}
if (deep[u] > deep[v]){
swap(u, v);
}
Modify(id[u], id[v],val, 1);
}
Node Query(int l, int r, int k){
//求区间有多少段颜色。并且保存这段区间左端点和右端点的颜色
if (Seg[k].st == l&&Seg[k].ed == r){
return Seg[k];
}
Node ans;
pushDown(k);
if (r <= Seg[L(k)].ed){
ans = Query(l, r, L(k));
}
else if (l >= Seg[R(k)].st){
ans = Query(l, r, R(k));
}
else{
Node ansL= Query(l, Seg[L(k)].ed, L(k)),ansR=Query(Seg[R(k)].st,r,R(k));
ans.val = ansL.val + ansR.val;
ans.lcolor = ansL.lcolor; ans.rcolor = ansR.rcolor;
if (ansL.rcolor == ansR.lcolor){
ans.val--;
}
}
pushUp(k);
return ans;
}
int Query(int u, int v){
int ans = 0,Lrc=-1,Rlc=-1;
//保存上次询问时两端区间查询时deep比较小的点的颜色，因为可能两端同时上升爬
int f1 = top[u], f2 = top[v];
while (f1 != f2){
if (deep[f1] < deep[f2]){
swap(f1, f2);
swap(u, v);
swap(Lrc, Rlc);
}
Node temp = Query(id[f1], id[u], 1);
ans += temp.val - (Lrc == temp.rcolor);
u = fa[f1]; f1 = top[u]; Lrc = temp.lcolor;
}
if (deep[u] > deep[v]){
swap(u, v);
swap(Lrc, Rlc);
}
Node temp = Query(id[u], id[v], 1);
ans += temp.val - (temp.rcolor == Rlc) - (temp.lcolor == Lrc);
return ans;
}
int main(){
//#ifdef kirito
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
//#endif
//    int start = clock();
int n,m;
while (~scanf("%d%d",&n,&m)){
Init();
for (int i = 1; i <= n; i++){
scanf("%d", &value[i]);
}
for (int i = 1; i < n; i++){
int u, v;
scanf("%d%d", &u, &v);
}
DFS1(1, 1, 0);  DFS2(1, 1); Build(1, n, 1);
while (m--){
char ope[10];
int u, v, w;
scanf("%s", ope);
switch (ope[0]){
case 'C': scanf("%d%d%d", &u, &v, &w); Modify(u, v, w); break;
default: scanf("%d%d", &u, &v); printf("%d\n", Query(u, v)); break;
}
}
}
//#ifdef LOCAL_TIME
//    cout << "[Finished in " << clock() - start << " ms]" << endl;
//#endif
return 0;
}

posted @ 2017-03-04 11:16  キリト  阅读(138)  评论(0编辑  收藏  举报