BZOJ3159 决战
题意
分析
树剖套平衡树。
难点在于路径翻转,其他的线段树都可以解决。
考虑套Splay,随便想想这操作就是将\(O(\log n)\)的区间翻转,翻转一个耗时\(O(\log n)\),所以总复杂度是\(O(\log^2 n)\)的。
然而你仔细想想貌似没有那么简单,主要是代码很烦,这么那么对应的。
注意到这题的性质,X国司令的操作的起点和终点的选取,都十分的睿智,这为我们简化代码提供了条件。若以r为根来树剖,那么这些区间端点的dfn是有序的,因为祖先的dfn小于后代的dfn。
然后就可以方便的将带翻转的区间提取出来,合并成一棵树,翻转一下,再拆分回去,最后合并起来即为新树。
时间复杂度\(O(n \log^2 n)\)。
打代码的时候我努力追求码风,然后每个细节都考虑的非常清楚,交上去竟然一遍AC了。自我感觉良好。
代码
我用函数式Treap实现了Splay。(话说Splay现在除了在LCT里面有用之外就是个废物)
我没有卡常,我也不喜欢卡常。
#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read() {
rg T data=0;
rg int w=1;
rg char ch=getchar();
while(!isdigit(ch)) {
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch)) {
data=data*10+ch-'0';
ch=getchar();
}
return data*w;
}
template<class T>il T read(rg T&x) {
return x=read<T>();
}
typedef long long ll;
co int N=5e4+7;
int root,tot;
namespace T {
int ch[N][2],siz[N],pri[N];
ll val[N],sum[N],max[N],min[N],tag[N];
bool rev[N];
int newnode(ll v) {
int x=++tot;
ch[x][0]=ch[x][1]=0,siz[x]=1,pri[x]=rand();
val[x]=sum[x]=v;
max[x]=min[x]=v;
tag[x]=rev[x]=0;
return x;
}
void pushup(int x) {
siz[x]=siz[ch[x][0]]+1+siz[ch[x][1]];
sum[x]=sum[ch[x][0]]+val[x]+sum[ch[x][1]];
max[x]=std::max(max[ch[x][0]],std::max(val[x],max[ch[x][1]]));
min[x]=std::min(min[ch[x][0]],std::min(val[x],min[ch[x][1]]));
}
void rever(int x) {
std::swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
void add(int x,ll v) {
val[x]+=v;
sum[x]+=siz[x]*v;
max[x]+=v;
min[x]+=v;
tag[x]+=v;
}
void pushdown(int x) {
if(rev[x]) {
if(ch[x][0])
rever(ch[x][0]);
if(ch[x][1])
rever(ch[x][1]);
rev[x]=0;
}
if(tag[x]) {
if(ch[x][0])
add(ch[x][0],tag[x]);
if(ch[x][1])
add(ch[x][1],tag[x]);
tag[x]=0;
}
}
void split(int x,int k,int&l,int&r) {
if(!x) {
l=r=0;
return;
}
if(siz[ch[x][0]]+1<=k) {
l=x;
pushdown(l);
split(ch[l][1],k-siz[ch[x][0]]-1,ch[l][1],r);
pushup(l);
} else {
r=x;
pushdown(r);
split(ch[r][0],k,l,ch[r][0]);
pushup(r);
}
}
int merge(int x,int y) {
if(!x||!y)
return x+y;
if(pri[x]>pri[y]) {
pushdown(x);
ch[x][1]=merge(ch[x][1],y);
pushup(x);
return x;
} else {
pushdown(y);
ch[y][0]=merge(x,ch[y][0]);
pushup(y);
return y;
}
}
void Increase(int&t,int l,int r,ll v) {
int x,y,z;
split(t,l-1,x,y);
split(y,r-l+1,y,z);
if(y)
add(y,v);
t=merge(x,merge(y,z));
}
ll Sum(int&t,int l,int r) {
int x,y,z;
split(t,l-1,x,y);
split(y,r-l+1,y,z);
ll res=sum[y];
t=merge(x,merge(y,z));
return res;
}
ll Major(int&t,int l,int r) {
int x,y,z;
split(t,l-1,x,y);
split(y,r-l+1,y,z);
ll res=max[y];
t=merge(x,merge(y,z));
return res;
}
ll Minor(int&t,int l,int r) {
int x,y,z;
split(t,l-1,x,y);
split(y,r-l+1,y,z);
ll res=min[y];
t=merge(x,merge(y,z));
return res;
}
typedef std::pair<int,int> pii;
typedef std::vector<pii> path;
typedef std::vector<int> subtree;
void Invert(int&t,path p) {
subtree s;
s.push_back(t);
for(int i=p.size()-1; i>=0; --i) {
int x=s.back(),l,r;
s.pop_back();
split(x,p[i].second,x,r);
split(x,p[i].first-1,l,x);
s.push_back(r);
s.push_back(x);
s.push_back(l);
}
reverse(s.begin(),s.end());
for(int i=1; i<p.size(); ++i)
s[1]=merge(s[1],s[2*i+1]);
rever(s[1]);
for(int i=p.size()-1; i; --i)
split(s[1],siz[s[1]]-(p[i].second-p[i].first+1),s[1],s[2*i+1]);
for(int i=1; i<s.size(); ++i)
s[0]=merge(s[0],s[i]);
t=s[0];
}
}
int n,m,r;
std::vector<int>g[N];
int dep[N],siz[N],fa[N],son[N];
void dfs1(int x,int fa) {
dep[x]=dep[fa]+1,siz[x]=1,::fa[x]=fa;
for(int i=0; i<g[x].size(); ++i) {
int y=g[x][i];
if(y==fa)
continue;
dfs1(y,x);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]])
son[x]=y;
}
}
int dfn[N],id,top[N];
void dfs2(int x,int top) {
dfn[x]=++id,::top[x]=top;
if(!son[x])
return;
dfs2(son[x],top);
for(int i=0; i<g[x].size(); ++i) {
int y=g[x][i];
if(y==fa[x]||y==son[x])
continue;
dfs2(y,y);
}
}
void Increase(int x,int y,ll v) {
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]])
std::swap(x,y);
T::Increase(root,dfn[top[x]],dfn[x],v);
x=fa[top[x]];
}
if(dep[x]>dep[y])
std::swap(x,y);
T::Increase(root,dfn[x],dfn[y],v);
}
ll Sum(int x,int y) {
ll res=0;
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]])
std::swap(x,y);
res+=T::Sum(root,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y])
std::swap(x,y);
res+=T::Sum(root,dfn[x],dfn[y]);
return res;
}
ll Major(int x,int y) {
ll res=0;
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]])
std::swap(x,y);
res=std::max(res,T::Major(root,dfn[top[x]],dfn[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y])
std::swap(x,y);
res=std::max(res,T::Major(root,dfn[x],dfn[y]));
return res;
}
ll Minor(int x,int y) {
ll res=5e7;
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]])
std::swap(x,y);
res=std::min(res,T::Minor(root,dfn[top[x]],dfn[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y])
std::swap(x,y);
res=std::min(res,T::Minor(root,dfn[x],dfn[y]));
return res;
}
void Invert(int x,int y) {
T::path p;
while(top[y]!=top[x]) {
p.push_back(T::pii(dfn[top[y]],dfn[y]));
y=fa[top[y]];
}
p.push_back(T::pii(dfn[x],dfn[y]));
reverse(p.begin(),p.end());
T::Invert(root,p);
}
int main() {
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(n),read(m),read(r);
for(int i=1; i<n; ++i) {
int x,y;
read(x),read(y);
g[x].push_back(y),g[y].push_back(x);
}
dfs1(r,0);
dfs2(r,r);
T::min[0]=5e7;
for(int i=1; i<=n; ++i)
root=T::merge(root,T::newnode(0));
while(m--) {
std::string cmd;
std::cin>>cmd;
if(cmd=="Increase") {
int x,y,w;
read(x),read(y),read(w);
Increase(x,y,w);
} else if(cmd=="Sum") {
int x,y;
read(x),read(y);
printf("%lld\n",Sum(x,y));
} else if(cmd=="Major") {
int x,y;
read(x),read(y);
printf("%lld\n",Major(x,y));
} else if(cmd=="Minor") {
int x,y;
read(x),read(y);
printf("%lld\n",Minor(x,y));
} else if(cmd=="Invert") { // utilize the feature
int x,y;
read(x),read(y);
Invert(x,y);
} else
assert(0);
}
return 0;
}
静渊以有谋,疏通而知事。