题目链接? ——————————————>这里———–>还有这里
题目描述 Description
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
输入描述 Input Description
第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面n-1行每行包含两个整数 和 ,表示x和y之间有一条无向边。
下面m行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
输出描述 Output Description
对于每个询问操作,输出一行答案。
样例输入 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
数据范围
边10W,点1W
题解
链剖练习题了……
这题如果不是树而是区间,就是个线段树傻逼题,然而这题弄到了树上,既然线段树能做,还是在树上操作,就想到了链剖……
对于每个线段树节点记录,左儿子,右儿子,左端点颜色,右端点颜色,区间答案,以及flag,即
struct Tree{
int l,r,lc,rc,ans,flagc;//lc左端rc右端 颜色 flagc标记
}tree[size];
这样对于两个子区间:要不就是在区间相接的地方颜色相同,这种情况下,当前区间等于子区间色块和-1,;反之,答案等于子区间色块和~,如下图所示:
1 | 1 | 1 | 2 | 2 | 1 | 1 | 1 |
两个2是分属顶层的左儿子和右儿子,如果不加特判,那答案就变成了4,实际答案为3.
然后剩下的就是正常的线段树操作:change,ask,build,update,spread等,详见下面代码
这题恶心的地方在于,需要注意的地方特别多,第一个地方就是刚才说的那个地方,第二个就是在ask时:
if(l <= mid && mid < r && tree[lson].rc == tree[rson].lc) ans --;
这里的意思和上面一样,也是判断连续区间的部分;
第三个地方是在链剖查询部分,查询区间sum的时候:
if(getcolor(1,w[top[x]]) == getcolor(1,w[fa[top[x]]])) ans --;
这句话的意思是当前链的顶点与当前链顶点的父亲颜色是否相同,相同ans–;原因还是连续区间的问题,线段树能快速查询区间,但是如果有一种性质可以跨区间,就必须进行特判!
于是这题的思路就这么出来了~:
链剖,然后线段树处理链剖序列,跟一般链剖题一样,就是多加了点特判。
这题我调了半天的RE原因是………………是我读了n条边然而只有n-1条!!!!我这么做居然能A13个点……这数据我真是…………我只想说WTF。
链剖不好调,建议多打,多打,熟练,在第二次打的时候保证必须1a,这样考试的时候你才有可能调出来,因为考试紧张也可能GG了,所以熟练熟练,是最重要的,比你多做几个题甚至要重要23333~
下面附上我的代码~
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<deque>
#include<algorithm>
#define lson p<<1
#define rson p<<1|1
using namespace std;
const int size = 1000010;
const int INF = 2 << 28;
//add edge
int eto[size],head[size],next[size],tot;
void build(int f,int t)
{
eto[++tot] = t;
next[tot] = head[f];
head[f] = tot;
}
//tree pou
int fa[size],son[size],top[size],deep[size],siz[size],w[size];
int dfs_clock,pre[size];
void dfs(int u,int faa,int d)
{
fa[u] = faa,son[u] = 0,siz[u] = 1,deep[u] = d;
for(int i = head[u];i;i = next[i])
{
int v = eto[i];
if(v == faa) continue;
dfs(v,u,d+1);
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs2(int u,int faa)
{
w[u] = ++dfs_clock; top[u] = faa;
pre[w[u]] = u;
if(son[u]) dfs2(son[u],faa);
for(int i = head[u];i;i = next[i])
{
int v = eto[i];
if(v != fa[u] && v != son[u]) dfs2(v,v);
}
}
//xd tree
int n,m;
struct Tree{
int l,r,lc,rc,ans,flagc;//lc左端rc右端 颜色 flagc标记
}tree[size];
int color[size];
void update(int p)
{
tree[p].lc = tree[lson].lc;
tree[p].rc = tree[rson].rc;
if(tree[lson].rc == tree[rson].lc) tree[p].ans = tree[lson].ans + tree[rson].ans - 1;
else tree[p].ans = tree[lson].ans + tree[rson].ans;
}
void build(int p,int l,int r)
{
tree[p].l = l,tree[p].r = r;
if(l == r)
{
tree[p].lc = tree[p].rc = tree[p].flagc = color[pre[l]];///
tree[p].ans = 1;
return ;
}
int mid = (l + r) >> 1;
build(lson,l,mid);
build(rson,mid+1,r);
update(p);
}
void spread(int p)
{
if(tree[p].flagc)
{
tree[lson].lc = tree[lson].rc = tree[lson].flagc = tree[p].flagc;
tree[rson].lc = tree[rson].rc = tree[rson].flagc = tree[p].flagc;
tree[lson].ans = tree[rson].ans = 1;
tree[p].flagc = 0;
}
}
void change(int p,int l,int r,int c)
{
if(l <= tree[p].l && tree[p].r <= r)
{
tree[p].lc = tree[p].rc = tree[p].flagc = c;
tree[p].ans = 1;
return ;
}
spread(p);
int mid = (tree[p].l + tree[p].r) >> 1;
if(l <= mid) change(lson,l,r,c);
if(mid < r) change(rson,l,r,c);
update(p);
}
int ask(int p,int l,int r)
{
if(l <= tree[p].l && tree[p].r <= r) return tree[p].ans;
spread(p);
int ans = 0;
int mid = (tree[p].l + tree[p].r) >> 1;
if(l <= mid) ans += ask(lson,l,r);
if(mid < r) ans += ask(rson,l,r);
if(l <= mid && mid < r && tree[lson].rc == tree[rson].lc) ans --;
return ans;
}
void getchange(int x,int y,int c)
{
while(top[x] != top[y])
{
if(deep[top[x]] < deep[top[y]]) swap(x,y);
change(1,w[top[x]],w[x],c);
x = fa[top[x]];
}
if(deep[x] > deep[y]) swap(x,y);
change(1,w[x],w[y],c);
}
int getcolor(int p,int id)
{
if(tree[p].l == tree[p].r) return tree[p].lc;
spread(p);
int mid = (tree[p].l + tree[p].r) >> 1;
if(id <= mid) return getcolor(lson,id);
else return getcolor(rson,id);
}
int ask_ans(int x,int y)
{
int ans = 0;
while(top[x] != top[y])
{
if(deep[top[x]] < deep[top[y]]) swap(x,y);
ans += ask(1,w[top[x]],w[x]);
if(getcolor(1,w[top[x]]) == getcolor(1,w[fa[top[x]]])) ans --;
x = fa[top[x]];
}
if(deep[x] > deep[y]) swap(x,y);
ans += ask(1,w[x],w[y]);
return ans;
}
char c;
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i ++) scanf("%d",&color[i]);
for(int i = 1;i < n;i ++) /WTF!
{
int a,b;
scanf("%d%d",&a,&b);
build(a,b);
build(b,a);
}
dfs(1,1,1);
dfs2(1,1);
build(1,1,n);
while(m --)
{
cin>>c;
if(c == 'C')
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
getchange(a,b,c);
}
else
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",ask_ans(a,b));
}
}
return 0;
}
-END-