您的位置:首页 > 其它

BZOJ 2243 [SDOI2011]染色==树链剖分

2016-07-20 15:45 281 查看
题目传送门:233333

学会了树剖之后这道题就主要看线段树的本事了

先树剖,开线段树维护区间的颜色段数量以及最左端和最右端的颜色。

合并是考虑相邻的两种颜色,如果颜色相同则ans--。

在处理树剖时要看好哪一端颜色和哪一端相连,才可以正确的合并。

---------------------------乌龟天空游-----------------------------

最好在脑海里有一幅caili413的题解,来祝你AK虐全场--

---------------------------火星撞地球-----------------------------

最好在脑海里有一幅树剖的图像来帮助理解。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(j,k,l) for (int j=k;j<=l;j++)
#define N 200005

using namespace std;
struct _233{

int l,r,lc,rc,sum,flag;

} tr[N*5];
int n,m,T,lcl,as,rcl,cnt,a
,ne[N*2],to[N*2],st
;
int size
,fa
,deep
,son
,top
,dfn
,id
;

void add(int k,int l,int p){

to[p]=l;
ne[p]=st[k];
st[k]=p;

}

void dfs1(int rt,int dad){

size[rt]=1;
fa[rt]=dad;
deep[rt]=deep[dad]+1;
son[rt]=0;int _=0;
for (int i=st[rt];i!=0;i=ne[i])
if (to[i]!=dad){

dfs1(to[i],rt);
size[rt]+=size[to[i]];
if (size[to[i]]>_){

_=size[to[i]];
son[rt]=to[i];

}

}

}

void dfs2(int rt,bool qaz){

if (qaz) top[rt]=top[fa[rt]];
else top[rt]=rt;
dfn[++cnt]=rt;
id[rt]=cnt;
if (son[rt]>0) dfs2(son[rt],1);
for (int i=st[rt];i!=0;i=ne[i])
if (to[i]!=fa[rt]&&to[i]!=son[rt])
dfs2(to[i],0);

}

void stree(int k,int l,int r){ //建树

tr[k].flag=-1;
if (l==r){

tr[k].sum=1;
tr[k].lc=a[dfn[l]];
tr[k].rc=a[dfn[r]];
return;

}
tr[k].l=++cnt;
tr[k].r=++cnt;
stree(tr[k].l,l,(l+r)/2);
stree(tr[k].r,(l+r)/2+1,r);
tr[k].lc=tr[tr[k].l].lc;
tr[k].rc=tr[tr[k].r].rc;
tr[k].sum=tr[tr[k].l].sum+tr[tr[k].r].sum;
if (tr[tr[k].l].rc==tr[tr[k].r].lc) tr[k].sum--;

}

void work(int k,int l,int r,int o,int p,int s){

if (r<o||l>p) return;
if (tr[k].flag>=0){ //推标记

if (tr[k].l>0){

tr[tr[k].l].sum=1;
tr[tr[k].l].lc=tr[k].flag;
tr[tr[k].l].rc=tr[k].flag;
tr[tr[k].l].flag=tr[k].flag;

}
if (tr[k].r>0){

tr[tr[k].r].sum=1;
tr[tr[k].r].lc=tr[k].flag;
tr[tr[k].r].rc=tr[k].flag;
tr[tr[k].r].flag=tr[k].flag;

}
tr[k].flag=-1;

}
if (o<=l&&r<=p){

tr[k].sum=1;
tr[k].lc=s;
tr[k].rc=s;
tr[k].flag=s; //一手抽成千古恨
return;

}
work(tr[k].l,l,(l+r)/2,o,p,s);
work(tr[k].r,(l+r)/2+1,r,o,p,s);
tr[k].lc=tr[tr[k].l].lc;
tr[k].rc=tr[tr[k].r].rc;
tr[k].sum=tr[tr[k].l].sum+tr[tr[k].r].sum;
if (tr[tr[k].l].rc==tr[tr[k].r].lc) tr[k].sum--;

}

void change(int x,int y,int j){

for (;top[x]!=top[y];x=fa[top[x]]){

if (deep[top[x]]<deep[top[y]]) swap(x,y);
work(1,1,n,id[top[x]],id[x],j);

}
work(1,1,n,min(id[x],id[y]),max(id[x],id[y]),j);

}

void getans(int k,int l,int r,int o,int p){

//printf("%d %d %d %d %d\n",k,l,r,o,p);
if (r<o||l>p) return;
if (tr[k].flag>=0){ //推标记

if (tr[k].l>0){

tr[tr[k].l].sum=1;
tr[tr[k].l].lc=tr[k].flag;
tr[tr[k].l].rc=tr[k].flag;
tr[tr[k].l].flag=tr[k].flag;

}
if (tr[k].r>0){

tr[tr[k].r].sum=1;
tr[tr[k].r].lc=tr[k].flag;
tr[tr[k].r].rc=tr[k].flag;
tr[tr[k].r].flag=tr[k].flag;

}
tr[k].flag=-1;

}
if (o<=l&&r<=p){

as+=tr[k].sum;
//printf("!!!!%d %d %d\n",l,r,tr[k].sum);
if (tr[k].lc==rcl) as--;
if (lcl==-1) lcl=tr[k].lc;
rcl=tr[k].rc;
return;

}
getans(tr[k].l,l,(l+r)/2,o,p);
getans(tr[k].r,(l+r)/2+1,r,o,p);

}

int ask(int x,int y){

int las=0,lc=-1,ras=0,rc=-1; //分别为左边的答案,颜色,右边的答案,颜色
for (;top[x]!=top[y];x=fa[top[x]]){

//printf("%d %d %d %d\n",x,y,lc,las);
if (deep[top[x]]<deep[top[y]]){ //在左右交换时两边的颜色,答案均要交换

swap(x,y);
swap(las,ras);
swap(lc,rc);

}
lcl=-1;rcl=-1;as=0;
getans(1,1,n,id[top[x]],id[x]);
las+=as;
//printf("%d %d\n",lcl,rcl);
if (lc==rcl) las--;
lc=lcl;

}
if (deep[x]>deep[y]){

swap(x,y);
swap(las,ras);
swap(lc,rc);

}
//printf("%d %d %d %d %d\n",x,y,lc,las,ras);
lcl=-1;rcl=-1;as=0;
getans(1,1,n,id[x],id[y]);
las+=as;
if (lc==lcl) las--;
if (rc==rcl) las--;
//printf("%d %d %d %d\n",x,y,las,ras);
return las+ras;

}

int main(){

scanf("%d%d",&n,&T);
rep(i,1,n) scanf("%d",&a[i]);
rep(i,1,n-1){

int k,l;
scanf("%d%d",&k,&l);
add(k,l,2*i-1);add(l,k,2*i);

}
dfs1(1,0);
dfs2(1,0);
//printf("%d %d\n",id[3],id[5]);
cnt=1;
stree(1,1,n);
while (T--){

char ch=getchar();
while (ch<'A'||ch>'Z') ch=getchar();
if (ch=='Q'){

int k,l;
scanf("%d%d",&k,&l);
printf("%d\n",ask(k,l)); //处理询问

}
else{

int k,l,j;
scanf("%d%d%d",&k,&l,&j);
change(k,l,j); //处理修改

}

}
system("pause");

}

---------------------------乌龟天空游-----------------------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: