树链剖分把我写吐了.为了研究这个东西花费了我4天的时间.
后面我的代码是对的,然后用来对拍的所谓”题解”是错的,害得我把随机的数据手膜了好几遍.
一开始有写完过样例,提交直接A.
后来越写调的时间越长,用来对拍的别人的程序是错的,我自己都快方了.
将一棵子树覆盖为1,将一点到根路径上的点覆盖为0,询问一个点是1还是0.
有非常强大的诡异dfs可以A掉这题.
当然树剖就是裸题了.
#include //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
re0 x=0,f=1;rec c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=x*10+c-'0';
return x*(f?1:-1);
}
inline void read(rel &x){
x=0;re0 f=1;rec c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=x*10+c-'0';
x*=f?1:-1;
}
template <typename mitsuha>
inline int write(mitsuha x){
if (!x) return pc(48);
if (x<0) x=-x,pc('-');
re0 bit[20],i,p=0;
for (;x;x/=10) bit[++p]=x%10;
for (i=p;i;--i) pc(bit[i]+48);
}
inline char fuhao(){
rec c=gc();
for (;isspace(c);c=gc());
return c;
}
}using namespace chtholly;
using namespace std;
const int yuzu=5e5;
typedef int fuko[yuzu|10];
vector<int> lj[yuzu|10];
int n,m;
namespace shu_lian_pou_fen{
fuko sz,fa,dep,son,dfn,ord,top;int cnt;
void dfs1(int u,int f){
fa[u]=f,dep[u]=dep[f]+1,sz[u]=1;
for (int v:lj[u]) if (v^f){
dfs1(v,u),sz[u]+=sz[v];
if (sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int _top){
top[u]=_top,dfn[u]=++cnt,ord[cnt]=u;
if (son[u]) dfs2(son[u],_top);
for (int v:lj[u]){
if (v^fa[u]&&v!=son[u]) dfs2(v,v);
}
}
typedef int yuki[yuzu<<2|13];
struct segtree{
#define le rt<<1
#define ri le|1
#define ls le,l,mid
#define rs ri,mid+1,r
yuki val,lazy;
void build(int rt=1,int l=1,int r=n){
lazy[rt]=-1;
if (l==r) val[rt]=0;
else{
int mid=l+r>>1;
build(ls),build(rs);
val[rt]=0;
}
}
void push_down(int rt,int l,int r){
if (~lazy[rt]){
lazy[le]=lazy[ri]=lazy[rt];
val[le]=val[ri]=lazy[rt];
lazy[rt]=-1;
}
}
void update(int ql,int qr,int v,int rt=1,int l=1,int r=n){
if (ql>r||qrreturn;
if (ql<=l&&qr>=r) val[rt]=lazy[rt]=v;
else{
int mid=l+r>>1;
push_down(rt,l,r);
update(ql,qr,v,ls),update(ql,qr,v,rs);
}
}
int query(int u,int rt=1,int l=1,int r=n){
if (ur) return 1;
if (l==r) return val[rt];
int mid=l+r>>1;
push_down(rt,l,r);
return query(u,ls)&query(u,rs);
}
}my_;
void update(int u,int v){
for (;top[u]!=top[v];u=fa[top[u]]){
if (dep[top[u]]0);
}
if (dep[u]>dep[v]) swap(u,v);
my_.update(dfn[u],dfn[v],0);
}
int main(){
re0 i;
n=read();
for (i=1;iint u=read(),v=read();
lj[u].push_back(v);
lj[v].push_back(u);
}
dfs1(1,0),dfs2(1,1);
my_.build();
for (m=read();m--;){
int k=read(),u=read();
if (k==1){
my_.update(dfn[u],dfn[u]+sz[u]-1,1);
}
if (k==2){
update(1,u);
}
if (k==3){
write(my_.query(dfn[u])),pl;
}
}
}
}
int main(){
shu_lian_pou_fen::main();
}
单边修改,两点间边覆盖,两点间边加,两点间最大边权.
边权树剖需要稍微改一下,用一个过程preedge
事前准备一下.
用vector
不是很好存储边的序号,故此用邻接表来做.
线段树需要维护两个标记.
/*
void preedge()中将边所指两点的dep比较一下,把较深那点的点权赋值为该边的边权.
然后询问修改到最后的时候不要改dfn[u]就可以了.
*/
#include //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
re0 x=0,f=1;rec c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=x*10+c-'0';
return x*(f?1:-1);
}
inline void read(rel &x){
x=0;re0 f=1;rec c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=x*10+c-'0';
x*=f?1:-1;
}
template <typename mitsuha>
inline int write(mitsuha x){
if (!x) return pc(48);
if (x<0) x=-x,pc('-');
re0 bit[20],i,p=0;
for (;x;x/=10) bit[++p]=x%10;
for (i=p;i;--i) pc(bit[i]+48);
}
}using namespace chtholly;
using namespace std;
const int yuzu=1e5,inf=0x3f3f3f3f;
typedef int fuko[yuzu|10];
struct node{int fr,to,next,w;}edge[yuzu<<1|1];
int n=read(),ecnt;
namespace shu_lian_pou_fen{
fuko fa,dep,sz,top,dfn,ord,son,a,head;int cnt;
void addedge(int u,int v,int w){
edge[++ecnt]={u,v,head[u],w},head[u]=ecnt;
}
void dfs1(int u,int f){
fa[u]=f,sz[u]=1,dep[u]=dep[f]+1;
for (re0 i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if (v^f){
dfs1(v,u),sz[u]+=sz[v];
if (sz[v]>sz[son[u]]) son[u]=v;
}
}
}
void dfs2(int u,int _top){
top[u]=_top,dfn[u]=++cnt,ord[cnt]=u;
if (son[u]) dfs2(son[u],_top);
for (re0 i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if (v^fa[u]&&v!=son[u]) dfs2(v,v);
}
}
typedef int yuki[yuzu<<2|13];
struct segtree{
#define le rt<<1
#define ri le|1
#define ls le,l,mid
#define rs ri,mid+1,r
yuki val,cov,lazy;
void build(int rt=1,int l=1,int r=n){
cov[rt]=-1,lazy[rt]=0;
if (l==r) val[rt]=a[l];
else{
int mid=l+r>>1;
build(ls),build(rs);
val[rt]=max(val[le],val[ri]);
}
}
void push_down(int rt,int l,int r){
if (~cov[rt]){
cov[le]=cov[ri]=cov[rt];
val[le]=val[ri]=cov[rt];
lazy[le]=lazy[ri]=0;
cov[rt]=-1;
}
if (lazy[rt]){
lazy[le]+=lazy[rt],lazy[ri]+=lazy[rt];
val[le]+=lazy[rt],val[ri]+=lazy[rt];
lazy[rt]=0;
}
}
void cover(int ql,int qr,int v,int rt=1,int l=1,int r=n){
if (ql>r||qrreturn;
if (ql<=l&&qr>=r) val[rt]=cov[rt]=v,lazy[rt]=0;
else{
int mid=l+r>>1;
push_down(rt,l,r);
cover(ql,qr,v,ls),cover(ql,qr,v,rs);
val[rt]=max(val[le],val[ri]);
}
}
void add(int ql,int qr,int v,int rt=1,int l=1,int r=n){
if (ql>r||qrreturn;
if (ql<=l&&qr>=r) val[rt]+=v,lazy[rt]+=v;
else{
int mid=l+r>>1;
push_down(rt,l,r);
add(ql,qr,v,ls),add(ql,qr,v,rs);
val[rt]=max(val[le],val[ri]);
}
}
int query(int ql,int qr,int rt=1,int l=1,int r=n){
if (ql>r||qrreturn -inf;
if (ql<=l&&qr>=r) return val[rt];
int mid=l+r>>1;
push_down(rt,l,r);
return max(query(ql,qr,ls),query(ql,qr,rs));
}
}my_;
void preedge(){
for (re0 i=1;i<=ecnt;i+=2){
int &u=edge[i].fr,&v=edge[i].to;
if (dep[u]>dep[v]) swap(u,v);
a[dfn[v]]=edge[i].w;
}
}
void change(int k,int w){
int t=dfn[edge[(k<<1)-1].to];
my_.cover(t,t,w);
}
void cover(int u,int v,int w){
for (;top[u]!=top[v];u=fa[top[u]]){
if (dep[top[u]]if (dep[u]>dep[v]) swap(u,v);
my_.cover(dfn[u]+1,dfn[v],w);
}
void add(int u,int v,int w){
for (;top[u]!=top[v];u=fa[top[u]]){
if (dep[top[u]]if (dep[u]>dep[v]) swap(u,v);
my_.add(dfn[u]+1,dfn[v],w);
}
int q_max(int u,int v){
int ans=-inf;
for (;top[u]!=top[v];u=fa[top[u]]){
if (dep[top[u]]if (dep[u]>dep[v]) swap(u,v);
return max(ans,my_.query(dfn[u]+1,dfn[v]));
}
int main(){
re0 i;
for (i=1;iint u=read(),v=read(),w=read();
addedge(u,v,w),addedge(v,u,w);
}
dfs1(1,0),dfs2(1,1);
preedge();
my_.build();
char c[9];
for (;scanf("%s",c),c[1]!='t';){
int u=read(),v=read();
if (c[1]=='a'){//max
write(q_max(u,v)),pl;
}
if (c[1]=='o'){//cover
cover(u,v,read());
}
if (c[1]=='d'){//add
add(u,v,read());
}
if (c[1]=='h'){//change
change(u,v);
}
}
}
}
int main(){
shu_lian_pou_fen::main();
}
支持区间覆盖,子树最小值,换根.
其它东西很简单,换根是个什么操作呢?
显然我们不可能对于每一次换根都把整棵树重新暴力剖一遍.
我们可以思考一下.
对于询问的点u,我们考虑它与现在的根nowrt的关系.
如果它和现在的根相同,直接返回整棵树.
其余情况求一下这两点的最近公共祖先.
如果答案是u,把u在nowrt方向上的儿子提起来,发现答案就是整棵树去掉nowrt方向上的儿子的子树的其他部分.
剩下还是u的子树不变.
然后分类讨论就做完了.不要忘记树剖自带求lca的功能,不用再来一个倍增数组了.
最后是这个坑爹的inf,0x3f3f3f3f0x3f3f3f3f不对,21474836472147483647也不对,21000000002100000000反而对了.
#include //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
re0 x=0,f=1;rec c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=x*10+c-'0';
return x*(f?1:-1);
}
inline void read(rel &x){
x=0;re0 f=1;rec c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=x*10+c-'0';
x*=f?1:-1;
}
template <typename mitsuha>
inline int write(mitsuha x){
if (!x) return pc(48);
if (x<0) x=-x,pc('-');
re0 bit[20],i,p=0;
for (;x;x/=10) bit[++p]=x%10;
for (i=p;i;--i) pc(bit[i]+48);
}
inline char fuhao(){
rec c=gc();
for (;isspace(c);c=gc());
return c;
}
}using namespace chtholly;
using namespace std;
const int yuzu=1e5,inf=2100000000;
typedef int fuko[yuzu|10];
vector<int> lj[yuzu|10];
int n=read(),m=read();
namespace shu_lian_pou_fen{
fuko fa,sz,son,dep,top,dfn,ord,a;
int cnt,nowrt;
void dfs1(int u,int f){
fa[u]=f,sz[u]=1,dep[u]=dep[f]+1;
for (re0 i=0;iint v=lj[u][i];
if (v^f){
dfs1(v,u),sz[u]+=sz[v];
if (sz[v]>sz[son[u]]) son[u]=v;
}
}
}
void dfs2(int u,int _top){
top[u]=_top,dfn[u]=++cnt,ord[cnt]=u;
if (son[u]) dfs2(son[u],_top);
for (re0 i=0;iint v=lj[u][i];
if (!dfn[v]) dfs2(v,v);
}
}
void debug(){
re0 i;
for (i=1;i<=n;++i) write(fa[i]),p32;pl;
for (i=1;i<=n;++i) write(dep[i]),p32;pl;
for (i=1;i<=n;++i) write(son[i]),p32;pl;
for (i=1;i<=n;++i) write(sz[i]),p32;pl;
for (i=1;i<=n;++i) write(top[i]),p32;pl;
for (i=1;i<=n;++i) write(dfn[i]),p32;pl;
for (i=1;i<=n;++i) write(a[ord[i]]),p32;pl;
}
typedef int yuki[yuzu<<2|13];
struct segtree{
#define le rt<<1
#define ri le|1
#define ls le,l,mid
#define rs ri,mid+1,r
yuki val,lazy;
void build(int rt=1,int l=1,int r=n){
lazy[rt]=-1;
if (l==r) val[rt]=a[ord[l]];
else{
int mid=l+r>>1;
build(ls),build(rs);
val[rt]=min(val[le],val[ri]);
}
}
void push_down(int rt,int l,int r){
if (~lazy[rt]){
lazy[le]=lazy[ri]=lazy[rt];
val[le]=val[ri]=lazy[rt];
lazy[rt]=-1;
}
}
void update(int ql,int qr,int v,int rt=1,int l=1,int r=n){
if (ql>r||qrreturn;
if (ql<=l&&qr>=r){
val[rt]=lazy[rt]=v;
}else{
int mid=l+r>>1;
push_down(rt,l,r);
update(ql,qr,v,ls),update(ql,qr,v,rs);
val[rt]=min(val[le],val[ri]);
}
}
int query(int ql,int qr,int rt=1,int l=1,int r=n){
if (ql>r||qrreturn inf;
if (ql<=l&&qr>=r) return val[rt];
int mid=l+r>>1;
push_down(rt,l,r);
return min(query(ql,qr,ls),query(ql,qr,rs));
}
}my_;
int q_lca(int u,int v){
for (;top[u]!=top[v];u=fa[top[u]]){
if (dep[top[u]]return dep[u]//不断跳到所在链的顶端的父亲,最后看看u,v的深度谁大.
void update(int u,int v,int w){
for (;top[u]!=top[v];u=fa[top[u]]){
if (dep[top[u]]if (dep[u]>dep[v]) swap(u,v);
my_.update(dfn[u],dfn[v],w);
}
int solve(int u){
if (u==nowrt) return my_.val[1];
int lca=q_lca(u,nowrt);
if (lca==u){
int v;
for (re0 i=0;iif (v^fa[u]&&dfn[v]<=dfn[nowrt]&&dfn[v]+sz[v]-1>=dfn[nowrt]) break;
}
return min(my_.query(1,dfn[v]-1),my_.query(dfn[v]+sz[v],n));
}
return my_.query(dfn[u],dfn[u]+sz[u]-1);
}
int main(){
re0 i;
for (i=1;iint u=read(),v=read();
lj[u].push_back(v);
lj[v].push_back(u);
}
for (i=1;i<=n;++i) a[i]=read();
nowrt=read();
dfs1(1,0),dfs2(1,1);
my_.build();
//debug();
for (;m--;){
int op=read(),u=read();
if (op==1){
nowrt=u;
}
if (op==2){
int v=read();
update(u,v,read());
}
if (op==3){
write(solve(u)),pl;
}
}
}
}
int main(){
shu_lian_pou_fen::main();
}
这是洛谷原图. 经典题.区间覆盖不难,难的是询问颜色段数量.
/*
线段树每个节点存储该节点最左边是什么颜色lcol,最右边是什么颜色rcol,从左到右颜色段的数量cnt.
pushup的时候判一下左儿子右边的颜色和右儿子左边的颜色是否相同,如果相同cnt[rt]-1.
询问的时候特判一下,如果ql,qr只覆盖了左右两个儿子其中的一个,直接跳去询问那个儿子.
如果同时覆盖了两个儿子,判断一下左儿子右边的颜色和右儿子左边的颜色,相同-1.
那么在询问两点间的时候,处理两链之间的颜色段需要询问一下top[u]的颜色和fa[top[u]]的颜色,如果相同-1.询问颜色是单点查询了,非常简单.
*/
#include //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
re0 x=0,f=1;rec c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=x*10+c-'0';
return x*(f?1:-1);
}
inline void read(rel &x){
x=0;re0 f=1;rec c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=x*10+c-'0';
x*=f?1:-1;
}
template <typename mitsuha>
inline int write(mitsuha x){
if (!x) return pc(48);
if (x<0) x=-x,pc('-');
re0 bit[20],i,p=0;
for (;x;x/=10) bit[++p]=x%10;
for (i=p;i;--i) pc(bit[i]+48);
}
inline char fuhao(){
rec c=gc();
for (;isspace(c);c=gc());
return c;
}
}using namespace chtholly;
using namespace std;
const int yuzu=1e5;
typedef int fuko[yuzu|10];
vector<int> lj[yuzu|10];
int n=read(),m=read();
namespace shu_lian_pou_fen{
fuko sz,fa,dep,son,top,dfn,ord,col;int cnt;
void dfs1(int u,int f){
fa[u]=f,sz[u]=1,dep[u]=dep[f]+1;
for (re0 i=0;iint v=lj[u][i];
if (v^f){
dfs1(v,u),sz[u]+=sz[v];
if (sz[v]>sz[son[u]]) son[u]=v;
}
}
}
void dfs2(int u,int _top){
top[u]=_top,dfn[u]=++cnt,ord[cnt]=u;
if (son[u]) dfs2(son[u],_top);
for (re0 i=0;iint v=lj[u][i];
if (v^fa[u]&&v!=son[u]) dfs2(v,v);
}
}
typedef int karen[yuzu<<2|13];
struct segtree{
#define le rt<<1
#define ri le|1
#define ls le,l,mid
#define rs ri,mid+1,r
karen lcol,rcol,lazy,cnt;
void pushup(int rt){
lcol[rt]=lcol[le],rcol[rt]=rcol[ri];
cnt[rt]=cnt[le]+cnt[ri]-(rcol[le]==lcol[ri]);
}
void build(int rt=1,int l=1,int r=n){
lazy[rt]=-1;
if (l==r){
lcol[rt]=rcol[rt]=col[ord[l]];
cnt[rt]=1;
}else{
int mid=l+r>>1;
build(ls),build(rs);
pushup(rt);
}
}
void push_down(int rt,int l,int r){
if (~lazy[rt]){
lazy[le]=lazy[ri]=lazy[rt];
lcol[le]=rcol[le]=lazy[rt];
lcol[ri]=rcol[ri]=lazy[rt];
cnt[le]=cnt[ri]=1;
lazy[rt]=-1;
}
}
void update(int ql,int qr,int v,int rt=1,int l=1,int r=n){
if (ql>r||qrreturn;
if (ql<=l&&qr>=r){
lcol[rt]=rcol[rt]=v;
lazy[rt]=v;
cnt[rt]=1;
}else{
int mid=l+r>>1;
push_down(rt,l,r);
update(ql,qr,v,ls),update(ql,qr,v,rs);
pushup(rt);
}
}
int query(int ql,int qr,int rt=1,int l=1,int r=n){
if (ql<=l&&qr>=r) return cnt[rt];
int mid=l+r>>1,ans=0;
push_down(rt,l,r);
if (ql<=mid) ans+=query(ql,qr,ls);
if (qr>mid) ans+=query(ql,qr,rs);
return ans-(ql<=mid&&qr>mid?lcol[ri]==rcol[le]:0);
}
int get_col(int x,int rt=1,int l=1,int r=n){
if (l==r) return lcol[rt];
int mid=l+r>>1;
push_down(rt,l,r);
return mid>=x?get_col(x,ls):get_col(x,rs);
}
}my_;
int query(int u,int v){
int ans=0;
for (;top[u]!=top[v];u=fa[top[u]]){
if (dep[top[u]]int tmp=my_.get_col(dfn[top[u]])==my_.get_col(dfn[fa[top[u]]]);
ans+=my_.query(dfn[top[u]],dfn[u])-tmp;
}
if (dep[u]>dep[v]) swap(u,v);
return ans+my_.query(dfn[u],dfn[v]);
}
void update(int u,int v,int w){
for (;top[u]!=top[v];u=fa[top[u]]){
if (dep[top[u]]if (dep[u]>dep[v]) swap(u,v);
my_.update(dfn[u],dfn[v],w);
}
int main(){
re0 i;
for (i=1;i<=n;++i) col[i]=read();
for (i=1;iint u=read(),v=read();
lj[u].push_back(v);
lj[v].push_back(u);
}
dfs1(1,0),dfs2(1,1);
my_.build();
for (;m--;){
char op=fuhao();
int u=read(),v=read();
if (op=='Q'){
write(query(u,v)),pl;
}
else{
update(u,v,read());
}
}
}
}
int main(){
shu_lian_pou_fen::main();
}
比较忙,故此没有在代码中加注释,抱歉了.