bzoj2243: [SDOI2011]染色--线段树+树链剖分

此题代码量较大。。但是打起来很爽

原本不用lca做一直wa不知道为什么。。

后来改lca重打了一遍= =结果一遍就AC了orz

题目比较裸,也挺容易打,主要是因为思路可以比较清晰

另:加读入优化比没加快了1.3s。。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<algorithm>
  4 using namespace std;
  5 const int maxn = 100010;
  6 struct node{
  7     int l,r,lc,rc,sum,lz;
  8 }t[maxn*4];
  9 struct edge{
 10     int to,next;
 11 }e[maxn*2];
 12 int n,m,u,v,tot,cnt,logn=0;
 13 int head[maxn],son[maxn],pre[maxn],tree[maxn],top[maxn],dep[maxn],fa[maxn][30],size[maxn],col[maxn];
 14
 15 inline void read(int &x){
 16     char cc=getchar(); x=0; int f=1;
 17     while (cc<‘0‘ || cc>‘9‘){if (cc==‘-‘) f=-1; cc=getchar();}
 18     while (cc>=‘0‘ && cc<=‘9‘) x=x*10+cc-‘0‘,cc=getchar(); x*=f;
 19 }
 20
 21 inline void insert(int u, int v){
 22     e[++tot].to=v; e[tot].next=head[u]; head[u]=tot;
 23 }
 24
 25 inline void dfs1(int u, int f, int d){
 26     size[u]=1; fa[u][0]=f; dep[u]=d;
 27     for (int i=1; i<=logn; i++) fa[u][i]=fa[fa[u][i-1]][i-1];
 28     for (int i=head[u]; i!=-1; i=e[i].next){
 29         int v=e[i].to;
 30         if (v==f) continue;
 31         dfs1(v,u,d+1);
 32         size[u]+=size[v];
 33         if (!son[u] || size[v]>size[son[u]]) son[u]=v;
 34     }
 35 }
 36
 37 inline void dfs2(int u, int num){
 38     top[u]=num; tree[u]=++cnt;
 39     pre[cnt]=u;
 40     if (!son[u]) return;
 41     dfs2(son[u],num);
 42     for (int i=head[u]; i!=-1; i=e[i].next)
 43         if (e[i].to!=fa[u][0] && e[i].to!=son[u])
 44             dfs2(e[i].to,e[i].to);
 45 }
 46
 47 inline int lca(int u, int v){
 48     if (dep[u]>dep[v]) swap(u,v);
 49     while (dep[u]<dep[v]){
 50         for (int i=logn; i>=0; i--)
 51             if (dep[u]<dep[fa[v][i]])
 52                 v=fa[v][i];
 53         v=fa[v][0];
 54     }
 55     if (u==v) return u;
 56     for (int i=logn; i>=0; i--)
 57         if (fa[u][i]!=fa[v][i]){
 58             u=fa[u][i];
 59             v=fa[v][i];
 60         }
 61     u=fa[u][0];
 62     return u;
 63 }
 64
 65 inline void pushdown(int x){
 66     if (t[x].lz){
 67         t[x<<1].lz=t[x<<1|1].lz=t[x].lz;
 68         t[x<<1].lc=t[x<<1].rc=t[x<<1|1].lc=t[x<<1|1].rc=t[x].lz;
 69         t[x<<1].sum=t[x<<1|1].sum=1;
 70         t[x].lz=0;
 71     }
 72 }
 73
 74 inline void pushup(int x){
 75     t[x].lc=t[x<<1].lc; t[x].rc=t[x<<1|1].rc;
 76     t[x].sum=t[x<<1].sum+t[x<<1|1].sum-(t[x<<1].rc==t[x<<1|1].lc);
 77 }
 78
 79 inline int query(int a, int b, int x){
 80     int l=t[x].l, r=t[x].r;
 81     if (a==l && r==b) return t[x].sum;
 82     int mid=l+r>>1;
 83     pushdown(x);
 84     if (b<=mid) return query(a,b,x<<1);
 85     else if (a>mid) return query(a,b,x<<1|1);
 86     else return query(a,mid,x<<1)+query(mid+1,b,x<<1|1)-(t[x<<1].rc==t[x<<1|1].lc);
 87 }
 88
 89 inline void update(int a, int b, int c, int x){
 90     int l=t[x].l, r=t[x].r;
 91     if (a==l && r==b){
 92         t[x].lc=t[x].rc=t[x].lz=c;
 93         t[x].sum=1;
 94         return;
 95     }
 96     int mid=l+r>>1;
 97     pushdown(x);
 98     if (b<=mid) update(a,b,c,x<<1);
 99     else if (a>mid) update(a,b,c,x<<1|1);
100     else{
101         update(a,mid,c,x<<1);
102         update(mid+1,b,c,x<<1|1);
103     }
104     pushup(x);
105 }
106
107 inline int get_col(int a, int x){
108     int l=t[x].l, r=t[x].r;
109     if (l==r) return t[x].lc;
110     pushdown(x);
111     int mid=l+r>>1;
112     if (a<=mid) return get_col(a,x<<1);
113     else return get_col(a,x<<1|1);
114 }
115
116 inline void build(int l, int r, int x){
117     t[x].l=l; t[x].r=r;
118     if (l==r){
119         t[x].lc=t[x].rc=col[pre[l]];
120         t[x].sum=1;
121         return;
122     }
123     int mid=l+r>>1;
124     if (l<=mid) build(l,mid,x<<1);
125     if (r>mid) build(mid+1,r,x<<1|1);
126     pushup(x);
127 }
128
129 inline void change(int x, int f, int c){
130     while (top[x]!=top[f]){
131         update(tree[top[x]],tree[x],c,1);
132         x=fa[top[x]][0];
133     }
134     update(tree[f],tree[x],c,1);
135 }
136
137 inline int get_sum(int x, int f){
138     int res=0;
139     while (top[x]!=top[f]){
140         res+=query(tree[top[x]],tree[x],1);
141         if (get_col(tree[top[x]],1)==get_col(tree[fa[top[x]][0]],1)) res--;
142         x=fa[top[x]][0];
143     }
144     res+=query(tree[f],tree[x],1);
145     return res;
146 }
147
148 int main(){
149     read(n); read(m);
150     while ((1<<logn)<n) logn++;
151     for (int i=1; i<=n; i++) read(col[i]),col[i]++;
152     tot=-1; memset(head,-1,sizeof(head));
153     for (int i=1; i<n; i++){
154         read(u); read(v);
155         insert(u,v); insert(v,u);
156     }
157     cnt=0;
158     dfs1(1,0,1); dfs2(1,0);
159     build(1,n,1);
160     char s[5];
161     while (m--){
162         scanf("%s", s);
163         if (s[0]==‘Q‘){
164             read(u); read(v);
165             int t=lca(u,v);
166             printf("%d\n", get_sum(u,t)+get_sum(v,t)-1);
167         }
168         else{
169             int color;
170             read(u); read(v); read(color);
171             int t=lca(u,v);
172             color++;
173             change(u,t,color);
174             change(v,t,color);
175         }
176     }
177     return 0;
178 }
时间: 2024-11-03 20:54:06

bzoj2243: [SDOI2011]染色--线段树+树链剖分的相关文章

[BZOJ2243][SDOI2011]染色 解题报告|树链剖分

Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. 与上一题差别不大,主要就是solve过程要根据左端点和右端点的颜色处理合并时候的情况 线段树的每个节点要记录颜色段数|最左边的颜色|最右边的颜色 同时往下传的时候标记要做好(之前那道题是单点修改所以不用考虑

bzoj2243 [SDOI2011]染色 动态树

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 110000 int pre[N],ch[N][2]; int e[N],ne[N*2],v[N*2]; int nn,m; int col[N]; int lc[N],sm[N],rc[N],num[N]; int rt[N],n; int qu[N

BZOJ2243 [SDOI2011]染色(树链剖分+线段树合并)

题目链接 BZOJ2243 树链剖分+线段树合并 线段树合并的一些细节需要注意一下 #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N = 100010; int n, m,

bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 7925  Solved: 2975[Submit][Status][Discuss] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完

[BZOJ2243]SDOI2011染色|树链剖分|LCT

裸题嘛.. 先考虑一条线段上如何查询颜色段数,只要对每个线段树节点多维护一个左颜色和右颜色,然后合并的时候sum[x]=sum[lc]+sum[rc]-(左儿子的右颜色==右儿子的左颜色)..实在太久没写树剖结果码+调试花了两节多晚自习,,各种傻逼错误,什么反向边忘加,标记忘记下传...还有就是更新答案的时候,关键的一点是要保证当前的两点(也就是a,b)是没有被更新到的,否则很难搞.. 表示LCT要更好写..不过在BZOJ上我的树链剖分6000+MS,LCT要13000+MS.. 树链剖分: #

【树链剖分】bzoj2243 [SDOI2011]染色

树链剖分模板题.线段树维护每个段中的颜色数.左端点颜色.右端点颜色. pushup: col[rt]=col[rt<<1]+col[rt<<1|1]-(Rcol[rt<<1]==Lcol[rt<<1|1]); 在合并各个链的答案时,要注意若两头颜色相同,ans--. [教训:树链剖分题在进行建立线段树树时,要注意下面代码中的标注部分.否则会WA] Code: 1 #include<cstdio> 2 #include<algorithm&g

【bzoj2243】[SDOI2011]染色  树链剖分 (区间合并处理)

2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 5143 Solved: 1919 [Submit][Status][Discuss] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如"112221"由3段组成:"11"."

[BZOJ2243][SDOI2011]染色(树链剖分)

[传送门] 树链剖分就行了,注意线段树上颜色的合并 Code #include <cstdio> #include <algorithm> #define N 100010 #define MID int mid=(l+r)>>1,ls=id<<1,rs=id<<1|1 #define len (r-l+1) using namespace std; struct tree{ int lc,rc,sum,tag; tree(){lc=rc=tag

BZOJ2243 [SDOI2011]染色

题意:树,路径染色,路径查询分了几段. 分析: 树链剖分套线段树,没写过,代码写得很乱,还犯了不少错,加了点注释,以后不能犯这种错了. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define m ((L+R)>>1) #define lc o<<1 #define rc o<<1|1 #define ls lc,L,m