题解报告——[SDOI2011]染色
Posted genius777
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解报告——[SDOI2011]染色相关的知识,希望对你有一定的参考价值。
题目描述
输入输出格式
输入格式:
输出格式:
对于每个询问操作,输出一行答案。
输入输出样例
说明
【思路分析】
看到这道题得第一想法就是树剖,很显然这确实是一道树剖的板题,但是却也是一个练习树剖的很好选择,至少我做完这道题对树剖又有了新的理解,其中也有很多细节需要注意的,考验调试能力。
首先我们用树剖维护树的链,用线段树维护链上权值。这里很好的是维护区间段数,而不是区间上的种类数,所有可以用线段树维护。
【细节注意】
这里我们会发现我们树剖其实是每次要将一条链分开,每一段单独进行查询,所以我们每次查询要比较这一次查询和上一段之间是否有同一段。
由于是树剖,我们每次后查询的区间,在线段树上一定是在前面,所以我们要比较本次查询的右端点和上一次查询的左端点
由于我们是从两个节点向LCA跳,所以我们要记录两个变量,lasta,lastb,分别表示上一次从某个方向跳来的链的端点颜色,然后进行比较即可
【代码实现】
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int maxn=1e5+5; 5 struct sd{ 6 int to,next; 7 }edge[maxn<<1]; 8 struct sd1{ 9 int l,r,son[2],sum,lkind,rkind,lazy; 10 }t[maxn<<2]; 11 int head[maxn],siz[maxn],top[maxn],mxson[maxn],dep[maxn],fa[maxn],id[maxn],ord[maxn],col[maxn],cnt,lnode,rnode; 12 void update(int v) 13 { 14 int ls=t[v].son[0],rs=t[v].son[1]; 15 t[v].sum=t[ls].sum+t[rs].sum; 16 if(t[ls].rkind==t[rs].lkind) t[v].sum--; 17 t[v].lkind=t[ls].lkind,t[v].rkind=t[rs].rkind; 18 } 19 void pushdown(int v) 20 { 21 if(t[v].lazy) 22 { 23 int ls=t[v].son[0],rs=t[v].son[1]; 24 if(ls) t[ls].sum=1,t[ls].lazy=t[ls].lkind=t[ls].rkind=t[v].lazy; 25 if(rs) t[rs].sum=1,t[rs].lazy=t[rs].lkind=t[rs].rkind=t[v].lazy; 26 t[v].lazy=0; 27 } 28 } 29 void build(int &v,int l,int r) 30 { 31 v=++cnt;t[v].l=l,t[v].r=r; 32 if(l==r) {t[v].lkind=t[v].rkind=col[ord[l]],t[v].sum=1;return;} 33 int mid=(l+r)>>1; 34 build(t[v].son[0],l,mid); 35 build(t[v].son[1],mid+1,r); 36 update(v); 37 } 38 void add_edge(int from,int to) 39 { 40 edge[++cnt].to=to; 41 edge[cnt].next=head[from]; 42 head[from]=cnt; 43 } 44 void dfs(int v,int ff,int deep) 45 { 46 fa[v]=ff,dep[v]=deep,siz[v]=1; 47 int MS=0,MX=0; 48 for(int i=head[v];i;i=edge[i].next) 49 { 50 int to=edge[i].to; 51 if(to!=ff) 52 { 53 dfs(to,v,deep+1); 54 if(MX<siz[to]) MX=siz[to],MS=to; 55 siz[v]+=siz[to]; 56 } 57 } 58 mxson[v]=MS; 59 } 60 void dfs2(int v,int tt) 61 { 62 top[v]=tt,ord[++cnt]=v,id[v]=cnt; 63 if(!mxson[v]) return; 64 dfs2(mxson[v],tt); 65 for(int i=head[v];i;i=edge[i].next) 66 { 67 if(edge[i].to!=fa[v]&&edge[i].to!=mxson[v]) 68 dfs2(edge[i].to,edge[i].to); 69 } 70 } 71 void change(int v,int l,int r,int kk) 72 { 73 if(t[v].l==l&&t[v].r==r) 74 { 75 t[v].sum=1,t[v].lkind=t[v].rkind=t[v].lazy=kk; 76 return; 77 } 78 pushdown(v); 79 int mid=(t[v].l+t[v].r)>>1,ls=t[v].son[0],rs=t[v].son[1]; 80 if(r<=mid) change(ls,l,r,kk); 81 else if(l>mid) change(rs,l,r,kk); 82 else change(ls,l,mid,kk),change(rs,mid+1,r,kk); 83 update(v); 84 } 85 int ask(int v,int l,int r,int ql,int qr) 86 { 87 pushdown(v); 88 if(t[v].l==l&&t[v].r==r) 89 { 90 if(t[v].l==ql) lnode=t[v].lkind; 91 if(t[v].r==qr) rnode=t[v].rkind; 92 return t[v].sum; 93 } 94 int mid=(t[v].l+t[v].r)>>1,ls=t[v].son[0],rs=t[v].son[1]; 95 if(r<=mid) return ask(ls,l,r,ql,qr); 96 else if(l>mid) return ask(rs,l,r,ql,qr); 97 else 98 { 99 int ans=0; 100 ans+=ask(ls,l,mid,ql,qr); 101 ans+=ask(rs,mid+1,r,ql,qr); 102 if(t[ls].rkind==t[rs].lkind) ans--; 103 return ans; 104 } 105 } 106 void LCA_change(int a,int b,int kk) 107 { 108 while(top[a]!=top[b]) 109 { 110 if(dep[top[a]]<dep[top[b]]) swap(a,b); 111 change(1,id[top[a]],id[a],kk); 112 a=fa[top[a]]; 113 } 114 if(dep[b]<dep[a]) swap(a,b); 115 change(1,id[a],id[b],kk); 116 } 117 int LCA_ask(int a,int b) 118 { 119 int ans=0,lasta=-1,lastb=-1; 120 while(top[a]!=top[b]) 121 { 122 if(dep[top[a]]>dep[top[b]]) 123 { 124 ans+=ask(1,id[top[a]],id[a],id[top[a]],id[a]); 125 if(rnode==lasta&&lasta!=-1) ans--; 126 lasta=lnode; 127 a=fa[top[a]]; 128 } 129 else 130 { 131 ans+=ask(1,id[top[b]],id[b],id[top[b]],id[b]); 132 if(rnode==lastb&&lastb!=-1) ans--; 133 lastb=lnode; 134 b=fa[top[b]]; 135 } 136 } 137 if(dep[a]<dep[b]) 138 { 139 ans+=ask(1,id[a],id[b],id[a],id[b]); 140 if(lasta==lnode) ans--; 141 if(lastb==rnode) ans--; 142 } 143 else 144 { 145 ans+=ask(1,id[b],id[a],id[b],id[a]); 146 if(lasta==rnode) ans--; 147 if(lastb==lnode) ans--; 148 } 149 return ans; 150 } 151 int main() 152 { 153 int n,m,a,b,c,rt; 154 scanf("%d%d",&n,&m); 155 for(int i=1;i<=n;i++) scanf("%d",&col[i]); 156 for(int i=1;i<n;i++) scanf("%d%d",&a,&b),add_edge(a,b),add_edge(b,a); 157 cnt=0,dfs(1,0,1),dfs2(1,1); 158 cnt=0,build(rt,1,n); 159 while(m--) 160 { 161 char ch[3]; 162 scanf("%s%d%d",ch,&a,&b); 163 if(ch[0]==‘Q‘) printf("%d ",LCA_ask(a,b)); 164 else scanf("%d",&c),LCA_change(a,b,c); 165 } 166 return 0; 167 }
以上是关于题解报告——[SDOI2011]染色的主要内容,如果未能解决你的问题,请参考以下文章