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");
}
---------------------------乌龟天空游-----------------------------
学会了树剖之后这道题就主要看线段树的本事了
先树剖,开线段树维护区间的颜色段数量以及最左端和最右端的颜色。
合并是考虑相邻的两种颜色,如果颜色相同则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");
}
---------------------------乌龟天空游-----------------------------
相关文章推荐
- Docker 容器逃逸案例分析
- [汇编]8086指令系统---串处理指令
- Java设计模式之装饰者模式
- getSession getHibernateTemplate用哪个
- hdu_5724_Chess(组合博弈)
- Struts的工作流程:
- Error:unsupported class file version 52.0问题的解决
- [汇编]8086指令系统---数据传送指令
- 【设计模式】java常用设计模式
- 在android studio中新建android gradle project的时候connect refused:connect或者卡在building project...或Refreshing
- Spring容器中Bean的作用域
- hdoj2504又见GCD
- android:RecycleView的简单封装使用
- Redis集群搭建详细过程整理备忘
- hdu_5724_Chess(组合博弈)
- [汇编]寄存器说明
- Intellij idea(pycharm,android studio)代码提示 设置不区分大小写
- ReentrantLock详解
- .NET 配置文件自定义
- jsp中获取properties文件内容