bzoj2243树链剖分+染色段数
2016-08-19 20:53
218 查看
终于做了一道不是一眼出思路的代码题(⊙o⊙)
之前没有接触过这种关于染色段数的题目(其实上课好像讲过),于是百度了一下(现在思维能力好弱)
实际上每一段有用的信息就是总共有几段和两段各是什么颜色,在开线段树的时候记录一下就好了
事实上我开了一个node,并且写了一个mix还是大大减小了代码量(对于我这种手残党来说同时大大减小了错误率)
由于前几题做的都是树链剖分,并没有在这一方面出问题,然而线段树还是不熟练,刚写完的时候居然忘记down了(mdzz)
对wa了N遍的总结:
由于是树上两个点间的路径,既有向上的路也有向下的路,然而树剖下来的结果是按深度排的,所以在链上跑的时候会发现一段链的左右(l和r)有时候是相反的,在合并几条链的时候一定要注意(事实证明我这么多遍wa全是因为没有翻转链)
对这一类问题的总结:
对于每一段都考虑有用(会对周围产生影响)的信息,在染色段数中就是两端(因为可能和隔壁合并)
之前没有接触过这种关于染色段数的题目(其实上课好像讲过),于是百度了一下(现在思维能力好弱)
实际上每一段有用的信息就是总共有几段和两段各是什么颜色,在开线段树的时候记录一下就好了
事实上我开了一个node,并且写了一个mix还是大大减小了代码量(对于我这种手残党来说同时大大减小了错误率)
由于前几题做的都是树链剖分,并没有在这一方面出问题,然而线段树还是不熟练,刚写完的时候居然忘记down了(mdzz)
对wa了N遍的总结:
由于是树上两个点间的路径,既有向上的路也有向下的路,然而树剖下来的结果是按深度排的,所以在链上跑的时候会发现一段链的左右(l和r)有时候是相反的,在合并几条链的时候一定要注意(事实证明我这么多遍wa全是因为没有翻转链)
对这一类问题的总结:
对于每一段都考虑有用(会对周围产生影响)的信息,在染色段数中就是两端(因为可能和隔壁合并)
//加了一大堆斜杠的是第一遍写之后补的 #include <cstdio> #include <iostream> #define mid (l+r)/2 using namespace std; int m=0,N=0,n,M,p,q,o; int to[200001],nex[200001],fir[100001],son[100001],bro[100001],co[100001]; int size[100001],l[100001],pos[100001],fa[100001],h[100001],top[100001]; struct node{int s,l,r;bool b;}t[500000],ans[2]; inline void add(int x,int y){to[++m]=y;nex[m]=fir[x];fir[x]=m;} inline node mix(node x,node y){return (node){x.s+y.s-(x.r==y.l),x.l,y.r,0};} int build(int now,int fat) { size[now]=1;fa[now]=fat;h[now]=h[fat]+1; for(int i=fir[now];i;i=nex[i]) if(to[i]!=fat) size[now]+=build(to[i],now),bro[to[i]]=son[now],son[now]=to[i]; return size[now]; } void pou(int now,int to) { l[++N]=now;pos[now]=N;top[now]=to; int max=son[now]; if(!max) return; for(int i=bro[max];i;i=bro[i]) if(size[i]>size[max]) max=i; pou(max,to); for(int i=son[now];i;i=bro[i]) if(i!=max) pou(i,i); } void down(int now)//////////////////////////// { if(t[now].b) { t[now].b=0;t[now*2].b=t[now*2+1].b=1; t[now*2].s=t[now*2+1].s=1; t[now*2].l=t[now*2].r=t[now*2+1].l=t[now*2+1].r=t[now].l; } } void work(int now,int l,int r,int x,int y,int z) { if(l==x && r==y) { t[now]=(node){1,z,z,1}; return;} down(now); if(x<=mid) work(now*2,l,mid,x,min(y,mid),z); if(y>mid) work(now*2+1,mid+1,r,max(x,mid+1),y,z); t[now]=mix(t[now*2],t[now*2+1]); } node que(int now,int l,int r,int x,int y) { if(l==x && r==y) return t[now]; down(now); if(y<=mid) return que(now*2,l,mid,x,y); if(x>mid) return que(now*2+1,mid+1,r,x,y); return mix(que(now*2,l,mid,x,mid),que(now*2+1,mid+1,r,mid+1,y)); } void solve(int x,int y,int z) { bool b=0;ans[0]=ans[1]=(node){0,-1,-1,0}; while(top[x]!=top[y]) { if(h[top[x]]<h[top[y]]) swap(x,y),b=!b; if(z==-1) { node tem=que(1,1,n,pos[top[x]],pos[x]); if(!b) swap(tem.l,tem.r);/////////////////////////////// if(ans[b].s==0) ans[b]=tem; else ans[b]=b?mix(tem,ans[b]):mix(ans[b],tem); } else work(1,1,n,pos[top[x]],pos[x],z); x=fa[top[x]]; } if(h[x]>h[y]) swap(x,y),b=!b;////////////////// if(z==-1) { node tem=que(1,1,n,pos[x],pos[y]);b=!b;//////////////// if(!b) swap(tem.l,tem.r); if(ans[b].s==0) ans[b]=tem; else ans[b]=b?mix(tem,ans[b]):mix(ans[b],tem); printf("%d\n",mix(ans[0],ans[1]).s); } else work(1,1,n,pos[x],pos[y],z); } int main() { scanf("%d%d",&n,&M); for(int i=1;i<=n;i++) scanf("%d",&co[i]); for(int i=1;i<n;i++) scanf("%d%d",&p,&q),add(p,q),add(q,p); build(1,0); pou(1,1); for(int i=1;i<=n;i++) work(1,1,n,pos[i],pos[i],co[i]); for(int i=1;i<=M;i++) { char ch=getchar(); while(ch!='C' && ch!='Q') ch=getchar(); if(ch=='C') scanf("%d%d%d",&p,&q,&o),solve(p,q,o); else scanf("%d%d",&p,&q),solve(p,q,-1); } return 0; }
相关文章推荐
- bzoj2243 [SDOI2011]染色(树链剖分,线段树求颜色段数)
- Bzoj 2243: [SDOI2011]染色 树链剖分,LCT,动态树
- bzoj2243 染色 树链剖分
- BZOJ 2243: [SDOI2011]染色 (树链剖分+线段树合并)
- Bzoj2243[SDOI2011]染色:树链剖分
- BZOJ 2243 [SDOI2011]染色 (树链剖分)(线段树区间修改)
- BZOJ 2243 SDOI 2011 染色 树链剖分
- 【bzoj 2243】染色(树链剖分)
- [省选] [树链剖分] [BZOJ2243] [SDOI2011] 染色
- BZOJ2243: [SDOI2011]染色 树链剖分
- [BZOJ 2243][SDOI2011] 染色 树链剖分 模板题
- BZOJ 2243 染色 [树链剖分]
- BZOJ 2243: [SDOI2011]染色 树链剖分
- 【bzoj2243】 [SDOI2011]染色 树链剖分+线段树
- bzoj 2243 树链剖分 染色
- BZOJ 2243 染色 | 树链剖分模板题进阶版
- BZOJ 2243 染色 树链剖分
- 【SDOI2011】【BZOJ2243】【树链剖分】染色
- 【bzoj2243】【sdoi2011】染色【树链剖分】
- [BZOJ 2243] [SDOI 2011] 染色 【树链剖分】