[bzoj 2243]: [SDOI2011]染色 [树链剖分][线段树]

Description

给定一棵有n个节点的无根树和m个操作,操作有2类:

1、将节点a到节点b路径上所有点都染成颜色c;

2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。

请你写一个程序依次完成这m个操作。

Input

第一行包含2个整数n和m,分别表示节点数和操作数;

第二行包含n个正整数表示n个节点的初始颜色

下面 行每行包含两个整数x和y,表示xy之间有一条无向边。

下面 行每行描述一个操作:

“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;

“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

Output

对于每个询问操作,输出一行答案。

Sample Input

6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5

Sample Output

3

1

2

HINT

数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。


My Solution

一道可爱的树链剖分题啊

注意区间合并和树剖中的calc即可

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 using namespace std;
  5
  6 inline int read(){
  7     char ch;
  8     int re=0;
  9     bool flag=0;
 10     while((ch=getchar())!=‘-‘&&(ch<‘0‘||ch>‘9‘));
 11     ch==‘-‘?flag=1:re=ch-‘0‘;
 12     while((ch=getchar())>=‘0‘&&ch<=‘9‘)  re=re*10+ch-‘0‘;
 13     return flag?-re:re;
 14 }
 15
 16 inline char rea(){
 17     char ch;
 18     while((ch=getchar())!=‘Q‘&&ch!=‘C‘);
 19     return ch;
 20 }
 21
 22 struct edge{
 23     int to,next;
 24     edge(int to=0,int next=0):
 25         to(to),next(next){}
 26 };
 27
 28 struct segment{
 29     int l,r,lc,rc,sum,tag;
 30 };
 31
 32 const int maxn=1e5+1;
 33
 34 edge edges[maxn<<1];
 35 segment tre[maxn<<2];
 36 int n,m,cnt=1,root;
 37 //si1,si2表示query操作中取到的最高和最低颜色
 38 int si1,si2,LL,RR;
 39 int head[maxn],data[maxn];
 40 int siz[maxn],fat[maxn],son[maxn],dep[maxn],id[maxn],id_[maxn],top[maxn];
 41
 42 inline void add_edge(int from,int to){
 43     edges[++cnt]=edge(to,head[from]);  head[from]=cnt;
 44     edges[++cnt]=edge(from,head[to]);  head[to]=cnt;
 45 }
 46
 47 void init(){
 48     n=read();  m=read();
 49     for(int i=1;i<=n;i++)  data[i]=read();
 50     int from,to;  cnt=0;
 51     for(int i=1;i<n;i++){
 52         from=read();  to=read();
 53         add_edge(from,to);
 54     }
 55 }
 56
 57 void dfs_1(int x,int fa){
 58     siz[x]=1;
 59     dep[x]=dep[fa]+1;
 60     fat[x]=fa;
 61     for(int ee=head[x];ee;ee=edges[ee].next)
 62         if(edges[ee].to!=fa){
 63             dfs_1(edges[ee].to,x);
 64             siz[x]+=siz[edges[ee].to];
 65             if(!son[x]||siz[edges[ee].to]>siz[son[x]])  son[x]=edges[ee].to;
 66         }
 67 }
 68
 69 void dfs_2(int x,int first){
 70     top[x]=first;
 71     id[x]=++cnt;
 72     id_[cnt]=x;
 73     if(!son[x])  return;
 74     dfs_2(son[x],first);
 75     for(int ee=head[x];ee;ee=edges[ee].next)
 76         if(edges[ee].to!=fat[x]&&edges[ee].to!=son[x])  dfs_2(edges[ee].to,edges[ee].to);
 77 }
 78
 79 void push_up(int x){
 80     int lson=x<<1,rson=lson|1;
 81     tre[x].lc=tre[lson].lc;
 82     tre[x].rc=tre[rson].rc;
 83     tre[x].sum=tre[lson].sum+tre[rson].sum-(tre[lson].rc==tre[rson].lc?1:0);
 84 }
 85
 86 void build(int x,int l,int r){
 87     tre[x].l=l;  tre[x].r=r;
 88     if(l==r){
 89         tre[x].lc=tre[x].rc=data[id_[l]];
 90         tre[x].sum=1;
 91         return;
 92     }
 93     int mid=(l+r)>>1;
 94     build(x<<1,l,mid);  build(x<<1|1,mid+1,r);
 95     push_up(x);
 96 }
 97
 98 void push_down(int x){
 99     int lson=x<<1,rson=lson|1;
100     int &c=tre[x].tag;
101     tre[lson].tag=tre[rson].tag=tre[lson].lc=
102     tre[lson].rc=tre[rson].lc=tre[rson].rc=c;
103     tre[lson].sum=1;  tre[rson].sum=1;
104     c=0;
105 }
106
107 void make(){
108     root=1;  dfs_1(root,0);
109     cnt=0;  dfs_2(root,root);
110     build(1,1,n);
111 }
112
113 void update(int x,int L,int R,int c){
114     if(L<=tre[x].l&&tre[x].r<=R){
115         tre[x].lc=tre[x].rc=tre[x].tag=c;
116         tre[x].sum=1;
117         return;
118     }
119
120     if(tre[x].tag)  push_down(x);
121
122     int mid=(tre[x].l+tre[x].r)>>1;
123     if(R<=mid)  update(x<<1,L,R,c);
124     else  if(L>mid)  update(x<<1|1,L,R,c);
125     else{
126         update(x<<1,L,mid,c);
127         update(x<<1|1,mid+1,R,c);
128     }
129     push_up(x);
130 }
131
132 int query_sum(int x,int L,int R){
133     if(tre[x].l==LL)  si1=tre[x].lc;
134     if(tre[x].r==RR)  si2=tre[x].rc;
135     if(L<=tre[x].l&&tre[x].r<=R)  return tre[x].sum;
136
137     if(tre[x].tag)  push_down(x);
138
139     int mid=(tre[x].l+tre[x].r)>>1;
140     if(R<=mid)  return query_sum(x<<1,L,R);
141     if(L>mid)  return query_sum(x<<1|1,L,R);
142     return query_sum(x<<1,L,mid)+query_sum(x<<1|1,mid+1,R)-(tre[x<<1].rc==tre[x<<1|1].lc?1:0);
143 }
144
145 void calc(int ss,int tt,int c){
146     int f1=top[ss],f2=top[tt];
147     while(f1!=f2){
148         if(dep[f1]<dep[f2]){  swap(f1,f2);  swap(ss,tt);  }
149         update(1,id[f1],id[ss],c);
150         ss=fat[f1];  f1=top[ss];
151     }
152     if(dep[ss]<dep[tt])  swap(ss,tt);
153     update(1,id[tt],id[ss],c);
154 }
155
156 int calc(int ss,int tt){
157     int f1=top[ss],f2=top[tt],ans=0;
158     int sid1=0,sid2=0;
159     while(f1!=f2){
160         if(dep[f1]<dep[f2]){  swap(f1,f2);  swap(ss,tt);  swap(sid1,sid2);  }
161         LL=id[f1];  RR=id[ss];
162         ans+=query_sum(1,id[f1],id[ss]);
163         if(si2==sid1)  ans--;
164         sid1=si1;  ss=fat[f1];  f1=top[ss];
165     }
166     if(dep[ss]<dep[tt])  {  swap(ss,tt);  swap(sid1,sid2);  }
167     LL=id[tt];  RR=id[ss];
168     ans+=query_sum(1,id[tt],id[ss]);
169     if(sid1==si2)  ans--;
170     if(sid2==si1)  ans--;
171     return ans;
172 }
173
174 void solve(){
175     char opt;
176     int ss,tt,c;
177     for(int i=0;i<m;i++){
178         opt=rea();
179         switch(opt){
180             case ‘C‘:{
181                 ss=read();  tt=read();  c=read();
182                 calc(ss,tt,c);
183                 break;
184             }
185             case ‘Q‘:{
186                 ss=read();  tt=read();
187                 printf("%d\n",calc(ss,tt));
188                 break;
189             }
190         }
191     }
192 }
193
194 int main(){
195     //freopen("data.in","r",stdin);
196     init();
197     make();
198     solve();
199     return 0;
200 }


それまでは 閉じこもって

あなたも卵の中なのね

时间: 2024-10-13 07:27:47

[bzoj 2243]: [SDOI2011]染色 [树链剖分][线段树]的相关文章

【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如"112221"由3段组成:"11"."222"和"1". 请你写一个程序依次完成这m个操作. Input 第一行包含2个整数n和m,分别表示节点数和操作数: 第二行包含n个正整数表示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】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

bzoj 2157: 旅游【树链剖分+线段树】

裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio> using namespace std; const int N=200005; int n,m,h[N],cnt,de[N],va[N],fa[N],si[N],hs[N],fr[N],id[N],tot,rl[N]; char c[10]; struct qwe { int ne,no,to,va

BZOJ2243 (树链剖分+线段树)

Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. 解题分析 树链剖分+线段树. 开一个记录类型,记录某一段区间的信息.l 表示区间最左侧的颜色 , r 表示区间最右侧的颜色 , sum 表示区间中颜色段数量. 合并时判断一下左区间的右端点和有区间的左端点的颜色是否一样. 树上合并时需要用两个变量ans1,ans2来存储.ans1表示x往上走时形成的链的信息,

【bzoj1959】[Ahoi2005]LANE 航线规划 离线处理+树链剖分+线段树

题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算机经过长期探测,已经锁定了Samuel星系中许多星球的空间坐标,并对这些星球从1开始编号1.2.3……. 一些先遣飞船已经出发,在星球之间开辟探险航线. 探险航线是双向的,例如从1号星球到3号星球开辟探险航线,那么从3号星球到1号星球也可以使用这条航线. 例如下图所示: 在5个星球之间,有5条探险航

Aizu 2450 Do use segment tree 树链剖分+线段树

Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show.php?pid=39566 Description Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and out

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

【bzoj3589】动态树 树链剖分+线段树

题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0:这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1:小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次. 输入 第一行一个整数n(1<=n<=200,000), 即节点数. 接下来n-1行, 每行两个数字u,

bzoj4304 (树链剖分+线段树)

Problem T2 (bzoj4304 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 解题分析 练手题.树链剖分+线段树. 参考程序 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #incl