[SDOI2011]染色

2243: [SDOI2011]染色

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 11290  Solved: 4392

题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=2243

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,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“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]之间。

 

题解

这题也算是树链剖分的一种经典模型吧,线段树只要记录该区间最左端点的值,最右端点的值,以及该区间的段数和就可以了。

合并的话,考虑下中间交接部分就行。

树剖的时候每段之间再判断一下交界处即可。

打完才发现原来再洛谷做过一遍了,竟然没有印象了,不过莫名比上次快了两秒,这次总时间3秒,上次5秒。

代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define ll long long
  4 #define N 200050
  5 int n,m,w[N];
  6 struct Edge{int from,to,s;}edges[N<<1];
  7 int tot,last[N];
  8 struct Tree{int l,r,lazy,lb,rb,sum;}tr[N<<2];
  9 int cnt,fa[N],dp[N],size[N],son[N],rk[N],kth[N],top[N];
 10 struct Query{int sum,lb,rb;};
 11 template<typename T>void read(T&x)
 12 {
 13   ll k=0; char c=getchar();
 14   x=0;
 15   while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
 16   if (c==EOF)exit(0);
 17   while(isdigit(c))x=x*10+c-'0',c=getchar();
 18   x=k?-x:x;
 19 }
 20 void read_char(char &c)
 21 {while(!isalpha(c=getchar())&&c!=EOF);}
 22 void AddEdge(int x,int y)
 23 {
 24   edges[++tot]=Edge{x,y,last[x]};
 25   last[x]=tot;
 26 }
 27 void push_up(int x)
 28 {
 29   Tree a=tr[x<<1],b=tr[x<<1|1];
 30   int len=tr[x].r-tr[x].l+1;
 31   if (len>1)
 32     {
 33       tr[x].sum=a.sum+b.sum-(a.rb==b.lb);
 34       tr[x].lb=a.lb;
 35       tr[x].rb=b.rb;
 36     }
 37   else tr[x].sum=0;
 38   if (tr[x].lazy!=-1)
 39     {tr[x].sum=1;tr[x].lb=tr[x].rb=tr[x].lazy;}
 40 }
 41 void push_down(int x)
 42 {
 43   if (tr[x].lazy==-1)return;
 44   tr[x<<1].lazy=tr[x].lazy;
 45   tr[x<<1|1].lazy=tr[x].lazy;
 46   push_up(x<<1);
 47   push_up(x<<1|1);
 48   tr[x].lazy=-1;
 49 }
 50 void bt(int x,int l,int r)
 51 {
 52   tr[x].l=l; tr[x].r=r; tr[x].lazy=-1;
 53   if (l==r)
 54     {
 55       tr[x].lb=tr[x].rb=w[kth[l]];
 56       tr[x].sum=1;
 57       return;
 58     }
 59   int mid=(l+r)>>1;
 60   bt(x<<1,l,mid);
 61   bt(x<<1|1,mid+1,r);
 62   push_up(x);
 63 }
 64 void update(int x,int l,int r,int tt)
 65 {
 66   if (l<=tr[x].l&&tr[x].r<=r)
 67     {
 68       tr[x].lazy=tt;
 69       push_up(x);
 70       return;
 71     }
 72   int mid=(tr[x].l+tr[x].r)>>1;
 73   push_down(x);
 74   if (l<=mid)update(x<<1,l,r,tt);
 75   if (mid<r)update(x<<1|1,l,r,tt);
 76   push_up(x);
 77 }
 78 Query query(int x,int l,int r)
 79 {
 80   if (l<=tr[x].l&&tr[x].r<=r)
 81     {
 82       return Query{tr[x].sum,tr[x].lb,tr[x].rb};
 83     }
 84   int mid=(tr[x].l+tr[x].r)>>1;
 85   Query tp1={0,-1,-1},tp2={0,-1,-1},tp;
 86   push_down(x);
 87   if (l<=mid)tp1=query(x<<1,l,r);
 88   if (mid<r)tp2=query(x<<1|1,l,r);
 89   push_up(x);
 90   tp.sum=tp1.sum+tp2.sum-(tp1.rb==tp2.lb);
 91   tp.lb=tp1.lb==-1?tp2.lb:tp1.lb;
 92   tp.rb=tp2.rb==-1?tp1.rb:tp2.rb;
 93   return tp;
 94 }
 95 void dfs1(int x,int pre)
 96 {
 97   fa[x]=pre;
 98   dp[x]=dp[pre]+1;
 99   size[x]=1;
100   son[x]=0;
101   for(int i=last[x];i;i=edges[i].s)
102     {
103       Edge &e=edges[i];
104       if (e.to==pre)continue;
105       dfs1(e.to,x);
106       size[x]+=size[e.to];
107       if (size[e.to]>size[son[x]])son[x]=e.to;
108     }
109 }
110 void dfs2(int x,int y)
111 {
112   rk[x]=++cnt;
113   kth[cnt]=x;
114   top[x]=y;
115   if(son[x]==0)return;
116   dfs2(son[x],y);
117   for(int i=last[x];i;i=edges[i].s)
118     {
119       Edge &e=edges[i];
120       if (e.to==fa[x]||e.to==son[x])continue;
121       dfs2(e.to,e.to);
122     }
123 }
124 void change(int x,int y,int tt)
125 {
126   int fx=top[x],fy=top[y];
127   while(fx!=fy)
128     {
129       if(dp[fx]<dp[fy])swap(x,y),swap(fx,fy);
130       update(1,rk[fx],rk[x],tt);
131       x=fa[fx];fx=top[x];
132     }
133   if (dp[x]<dp[y])swap(x,y);
134   update(1,rk[y],rk[x],tt);
135 }
136 int get_sum(int x,int y)
137 {
138   int fx=top[x],fy=top[y],lx=-1,ly=-1,ans=0;
139   Query tp;
140   while(fx!=fy)
141     {
142       if (dp[fx]<dp[fy])swap(x,y),swap(fx,fy),swap(lx,ly);
143       tp=query(1,rk[fx],rk[x]);
144       ans+=tp.sum-(tp.rb==lx);
145       lx=tp.lb; x=fa[fx]; fx=top[x];
146     }
147   if (dp[x]<dp[y])swap(x,y),swap(lx,ly);
148   tp=query(1,rk[y],rk[x]);
149   ans+=tp.sum-(tp.lb==ly)-(tp.rb==lx);
150   return ans;
151 }
152 int main()
153 {
154 #ifndef ONLINE_JUDGE
155   freopen("aa.in","r",stdin);
156 #endif
157   read(n); read(m);
158   for(int i=1;i<=n;i++)read(w[i]);
159   for(int i=1;i<=n-1;i++)
160     {
161       int x,y;
162       read(x); read(y);
163       AddEdge(x,y);
164       AddEdge(y,x);
165     }
166   dfs1(1,0);
167   dfs2(1,1);
168   bt(1,1,n);
169   for(int i=1;i<=m;i++)
170     {
171       char id; int x,y,tt;
172       read_char(id); read(x); read(y);
173       if(id=='C')
174     {
175       read(tt);
176       change(x,y,tt);
177     }
178       if (id=='Q')printf("%d\n",get_sum(x,y));
179     }
180 }
View Code

 

转载于:https://www.cnblogs.com/mmmqqdd/p/10769453.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值