【BZOJ2243】【SDOI2011】染色(树链剖分+线段树)
来源:互联网 发布:xampp mac使用教程 编辑:程序博客网 时间:2024/05/19 03:20
题目描述
传送门
题解
树链剖分一样就能看出来,更重要的是线段树的处理。
p数组与sum同步,.l/.r分别表示这个区间左端点和右端点的颜色。然后各种乱搞。
查询的时候,在链与链之间,如果颜色一样的话,则需要使当前答案-1。
一节微机课没搞出来,回去之后数学课想了一想,晚上终于调出来了。提交的时候行数200+,删去注释之后只有170+了。。。
代码
#include<iostream>#include<cstring>#include<cstdio>using namespace std;const int max_n=1e5+5;const int max_e=max_n*2;const int max_N=max_n*4;int n,m,x,y,N,u,t,ans;int color[max_n],size[max_n],h[max_n],father[max_n],son[max_n];int top[max_n],num[max_n],tree[max_n];int point[max_n],next[max_e],v[max_e],tot;int sum[max_N],delta[max_N],interval[max_n];struct hp{ int l,r;}p[max_N];inline void add(int x,int y){ ++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y; ++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x;}inline void dfs_1(int x,int fa,int dep){ size[x]=1; h[x]=dep; father[x]=fa; int maxson=0; for (int i=point[x];i;i=next[i]) if (v[i]!=fa){ dfs_1(v[i],x,dep+1); size[x]+=size[v[i]]; if (size[v[i]]>maxson){ maxson=size[v[i]]; son[x]=v[i]; } }}inline void dfs_2(int x,int fa){ if (son[fa]!=x) top[x]=x; else top[x]=top[fa]; num[x]=++N; if (son[x]) dfs_2(son[x],x); for (int i=point[x];i;i=next[i]) if (v[i]!=fa&&v[i]!=son[x]) dfs_2(v[i],x);}inline void update(int now){ if (p[now<<1].r==p[now<<1|1].l) sum[now]=sum[now<<1]+sum[now<<1|1]-1; else sum[now]=sum[now<<1]+sum[now<<1|1]; p[now].l=p[now<<1].l; p[now].r=p[now<<1|1].r;}inline void pushdown(int now,int l,int r,int mid){ if (delta[now]){ sum[now<<1]=1; delta[now<<1]=delta[now]; p[now<<1].l=p[now<<1].r=delta[now]; sum[now<<1|1]=1; delta[now<<1|1]=delta[now]; p[now<<1|1].l=p[now<<1|1].r=delta[now]; delta[now]=0; }}inline void build(int now,int l,int r){ int mid=(l+r)>>1; if (l==r){ interval[l]=now; sum[now]=1; p[now].l=p[now].r=color[tree[l]]; return; } build(now<<1,l,mid); build(now<<1|1,mid+1,r); update(now);}inline void interval_change(int now,int l,int r,int lrange,int rrange,int v){ int mid=(l+r)>>1; if (lrange<=l&&r<=rrange){ sum[now]=1; p[now].l=p[now].r=v; delta[now]=v; return; } pushdown(now,l,r,mid); if (lrange<=mid) interval_change(now<<1,l,mid,lrange,rrange,v); if (mid+1<=rrange) interval_change(now<<1|1,mid+1,r,lrange,rrange,v); update(now);}inline int query(int now,int l,int r,int lrange,int rrange){ int mid=(l+r)>>1,ans=0; if (lrange<=l&&r<=rrange) return sum[now]; pushdown(now,l,r,mid); bool pd1=false,pd2=false; if (lrange<=mid) ans+=query(now<<1,l,mid,lrange,rrange),pd1=true; if (mid+1<=rrange) ans+=query(now<<1|1,mid+1,r,lrange,rrange),pd2=true; if (pd1&&pd2&&p[now<<1].r==p[now<<1|1].l) ans--; return ans;}inline void CHANGE(int u,int t,int x){ int f1=top[u],f2=top[t]; while (f1!=f2){ if (h[f1]<h[f2]){ swap(u,t); swap(f1,f2); } interval_change(1,1,N,num[f1],num[u],x); u=father[f1]; f1=top[u]; } if (num[u]>num[t]) swap(u,t); interval_change(1,1,N,num[u],num[t],x);}inline int QUERY(int u,int t){ int f1=top[u],f2=top[t],ans=0; while (f1!=f2){ if (h[f1]<h[f2]){ swap(u,t); swap(f1,f2); } ans+=query(1,1,N,num[f1],num[u]); //pushdown int k=query(1,1,N,num[f1],num[f1]); k=query(1,1,N,num[father[f1]],num[father[f1]]); if (p[interval[num[f1]]].l==p[interval[num[father[f1]]]].l) ans--; u=father[f1]; f1=top[u]; } if (num[u]>num[t]) swap(u,t); ans+=query(1,1,N,num[u],num[t]); return ans;}int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;++i) scanf("%d",&color[i]); for (int i=1;i<n;++i){ scanf("%d%d",&x,&y); add(x,y); } dfs_1(1,0,1); dfs_2(1,0); for (int i=1;i<=n;++i) tree[num[i]]=i; build(1,1,N); for (int i=1;i<=m;++i){ char ch=getchar(); while (ch!='C'&&ch!='Q') ch=getchar(); if (ch=='C'){ scanf("%d%d%d",&u,&t,&x); CHANGE(u,t,x); } else{ scanf("%d%d",&u,&t); ans=QUERY(u,t); printf("%d\n",ans); } }}
总结
①关于线段树的任何操作(包括有时候乱搞的直接查询编号),都要思考一下有没有pushdown,即当前也许只是打了标记,没有更新到最新值。
②自己写input不要写错了。
0 0
- 【BZOJ2243】【SDOI2011】染色(树链剖分+线段树)
- bzoj2243: [SDOI2011]染色(树链剖分+线段树)
- 【bzoj2243】 [SDOI2011]染色 树链剖分+线段树
- 【BZOJ2243】[SDOI2011]染色【树链剖分】【线段树】
- bzoj2243 [SDOI2011]染色 (树链剖分+线段树)
- 树链剖分+线段树【SDOI2011】 bzoj2243 染色
- 【bzoj2243】【树链剖分】【线段树】SDOI2011染色
- [BZOJ2243][SDOI2011]染色(树剖+线段树)
- 【bzoj2243】[SDOI2011]染色(树链剖分)
- bzoj2243: [SDOI2011]染色 树链剖分
- 【BZOJ2243】[SDOI2011]染色 树链剖分
- 【BZOJ2243】【SDOI2011】染色 树链剖分
- 【SDOI2011】【BZOJ2243】【树链剖分】染色
- 【bzoj2243】【sdoi2011】染色【树链剖分】
- Bzoj2243[SDOI2011]染色:树链剖分
- [SDOI2011] [BZOJ2243] 染色 - 树链剖分
- BZOJ2243 【SDOI2011】染色 树链剖分
- BZOJ2243: [SDOI2011]染色 树链剖分
- java中ArrayList和class简介
- C++获取随机数的办法
- 工作感悟
- 蓝桥杯 — 基础练习 特殊回文数(思路+详解)
- 使用CocoaPods过程中的几个问题
- 【BZOJ2243】【SDOI2011】染色(树链剖分+线段树)
- WEB前端面试重点
- iOS block 小结
- c++ primer 第五版的Sales_data类
- 【学习C++】1.开始学习C++
- nyoj 236 心急的C小加
- 带有同步清0、同步置1的D触发器模块描述及其Testbench测试
- HDU Common Subsequence
- android 读写sd卡的权限设置