BZOJ 2243: [SDOI2011]染色
题解:树链剖分细节题 口胡一下LCT也是可以的 只要维护一段的左右两个端点的颜色和长度合并即可
树剖版本(入门的时候写的 好丑啊TAT)
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<cstring>
#include<cstdio>
#define N 200005
using namespace std;
vector<int>vec[N];
int pos;
int son[N];
int s[N];
int n,m;
void inte() {
pos=0;
for(int i=1; i<=n; i++) son[i]=-1;
return ;
}
int fa[N];
int num[N];
int deep[N];
void dfs(int v,int pre,int w) {
fa[v]=pre;
num[v]=1;
deep[v]=w;
for(int i=0; i<vec[v].size(); i++) {
int e=vec[v][i];
if(e!=pre) {
dfs(e,v,w+1);
num[v]+=num[e];
if(son[v]==-1||num[son[v]]<num[e]) {
son[v]=e;
}
}
}
}
int tp[N];
int p[N];
int fp[N];
void biaohao(int v,int sd) {
tp[v]=sd;
p[v]=++pos;
fp[p[v]]=v;
if(son[v]==-1) return ;
biaohao(son[v],sd);
for(int i=0; i<vec[v].size(); i++) {
int e=vec[v][i];
if(e!=fa[v]&&e!=son[v]) biaohao(e,e);
}
}
typedef struct node {
int first;
int end;
int l;
int r;
int flag;
int date;
} node;
node a[4*N];
void built(int root,int first,int end) {
if(first==end) {
a[root].first=first;
a[root].end=end;
a[root].l=s[fp[first]];
a[root].r=s[fp[first]];
a[root].flag=-1;
a[root].date=1;
//cout<<first<<" "<<a[root].l<<" "<<a[root].date<<endl;
return ;
}
int mid=(first+end)/2;
built(root*2,first,mid);
built(root*2+1,mid+1,end);
a[root].first=a[root*2].first;
a[root].end=a[root*2+1].end;
a[root].l=a[root*2].l;
a[root].r=a[root*2+1].r;
a[root].flag=-1;
if(a[root*2].r==a[root*2+1].l) a[root].date=a[root*2].date+a[root*2+1].date-1;
else a[root].date=a[root*2].date+a[root*2+1].date;
// cout<<a[root].l<<" "<<a[root].r<<" "<<a[root].date<<endl;
}
void U(int root,int first,int end,int l,int r,int e) {
if(p[l]<=first&&end<=p[r]) {
a[root].flag=-1;
a[root].l=e;
a[root].r=e;
a[root].date=1;
a[root*2].l=e;
a[root*2].r=e;
a[root*2].date=1;
a[root*2+1].l=e;
a[root*2+1].r=e;
a[root*2+1].date=1;
a[root*2].flag=e;
a[root*2+1].flag=e;
// cout<<a[root].l<<" "<<a[root].r<<" "<<a[root].date<<endl;
return ;
}
if(a[root].flag!=-1) {
a[root*2].l=a[root].flag;
a[root*2].r=a[root].flag;
a[root*2].date=1;
a[root*2+1].l=a[root].flag;
a[root*2+1].r=a[root].flag;
a[root*2+1].date=1;
a[root*2].flag=a[root].flag;
a[root*2+1].flag=a[root].flag;
a[root].flag=-1;
}
int mid=(first+end)/2;
if(p[l]<=mid) U(root*2,first,mid,l,r,e);
if(p[r]>mid) U(root*2+1,mid+1,end,l,r,e);
a[root].l=a[root*2].l;
a[root].r=a[root*2+1].r;
if(a[root*2].r==a[root*2+1].l) a[root].date=a[root*2].date+a[root*2+1].date-1;
else a[root].date=a[root*2].date+a[root*2+1].date;
}
int sum;
int p1;
int p2;
int c1;
int c2;
int jump;
int c3;
int cc1;
void Q(int root,int first,int end,int l,int r) {
if(a[root].flag!=-1) {
a[root*2].l=a[root].flag;
a[root*2].r=a[root].flag;
a[root*2].date=1;
a[root*2+1].l=a[root].flag;
a[root*2+1].r=a[root].flag;
a[root*2+1].date=1;
a[root*2].flag=a[root].flag;
a[root*2+1].flag=a[root].flag;
a[root].flag=-1;
}
if(p[l]==first){
if(jump==0) p1=a[root].l;
else c3=a[root].l;
}
if(end==p[r]){
if(jump==0) p2=a[root].r;
else p1=a[root].r;
}
if(p[l]<=first&&end<=p[r]) {
sum+=a[root].date;
return ;
}
int mid=(first+end)/2;
if(p[l]<=mid) Q(root*2,first,mid,l,r);
if(p[r]>mid) Q(root*2+1,mid+1,end,l,r);
if(p[l]<=mid&&mid<p[r]) sum-=(a[root*2].r==a[root*2+1].l);
a[root].l=a[root*2].l;
a[root].r=a[root*2+1].r;
if(a[root*2].r==a[root*2+1].l) a[root].date=a[root*2].date+a[root*2+1].date-1;
else a[root].date=a[root*2].date+a[root*2+1].date;
}
int Sum(int u,int v) {
int uu=tp[u];
int vv=tp[v];
sum=0;
jump=-1;
c1=-1;
c2=-1;
while(uu!=vv) {
if(deep[uu]<deep[vv]) {
swap(uu,vv);
swap(u,v);
swap(c1,c2);
}
Q(1,1,n,uu,u);
sum=sum-(c1==p1);
// cout<<"---------------------"<<sum<<endl;
c1=c3;
u=fa[uu];
uu=tp[u];
}
if(deep[u]>deep[v]) {
swap(c1,c2);
swap(u,v);
}
jump=0;
cc1=-1;
Q(1,1,n,u,v);
sum=sum-(c1==p1);
sum=sum-(c2==p2);
return sum;
}
void Up(int u,int v,int e) {
int uu=tp[u];
int vv=tp[v];
while(uu!=vv) {
if(deep[uu]<deep[vv]) {
swap(uu,vv);
swap(u,v);
}
U(1,1,n,uu,u,e);
u=fa[uu];
uu=tp[u];
}
if(deep[u]>deep[v]) swap(u,v);
U(1,1,n,u,v,e);
return ;
}
int main() {
// freopen("1.txt","r",stdin);
// freopen("2.txt","w",stdout);
scanf("%d%d",&n,&m);
inte();
int aa,bb;
for(int i=1; i<=n; i++) scanf("%d",&s[i]);
for(int i=1; i<n; i++) {
scanf("%d%d",&aa,&bb);
vec[aa].push_back(bb);
vec[bb].push_back(aa);
}
dfs(1,-1,1);
biaohao(1,1);
built(1,1,n);
char ch;
int u,v,e;
for(int i=1; i<=m; i++) {
scanf(" %c",&ch);
if(ch=='C') {
scanf("%d%d%d",&u,&v,&e);
Up(u,v,e);
} else if(ch=='Q') {
scanf("%d%d",&u,&v);
int t1=Sum(u,v);
printf("%d\n",t1);
}
}
return 0;
}
2243: [SDOI2011]染色
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 10354 Solved: 3969
[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]之间。

浙公网安备 33010602011771号