给出一棵N(N <= 10000)个点的树,要求支持:
1.改变第i条边的权值
2.求a->b上的最大边权
直接树剖或LCT即可
1.LCT(660ms)
#include
#include
#include
#include
#include
#define L(i) (T[i].s[0])
#define R(i) (T[i].s[1])
#define F(i) (T[i].fa)
#define For(i,j,k) for(register int i=(j);i<=(int)k;i++)
#define Forr(i,j,k) for(register int i=(j);i>=(int);i--)
#define Set(a,b) memset(a,b,sizeof(a))
#define Loc(i) (R(F(i))==i)
using namespace std;
const int N=20010;
inline void read(int &x){
x=0;char c=getchar();int f=(c=='-');
while(c<'0'||c>'9')c=getchar(),f!=(c=='-');
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
}
int Begin[N],Next[N*2],to[N*2],e,n,m;
struct node{
int s[2],fa,rev,v,mx;
};
struct LCT{
node T[N];
inline void clear(){Set(T,0);}
inline bool isrt(int x){
return R(F(x))!=x&&L(F(x))!=x;
}
inline void pushup(int x){
T[x].mx=max(max(T[L(x)].mx,T[R(x)].mx),T[x].v);
}
inline void pushdown(int x){
if(T[x].rev){
T[x].rev=0,T[L(x)].rev^=1,T[R(x)].rev^=1;
swap(L(x),R(x));
}
}
inline void Pushdown(int x){
if(!isrt(x))Pushdown(F(x));
pushdown(x);
}
inline void Rotate(int x){
int A=F(x),B=F(A),l=Loc(x),r=l^1,d=Loc(A);
if(!isrt(A))T[B].s[d]=x;F(x)=B;
F(A)=x,F(T[x].s[r])=A,T[A].s[l]=T[x].s[r],T[x].s[r]=A;
pushup(A),pushup(x);
}
inline void splay(int x){
Pushdown(x);
while(!isrt(x)){
if(!isrt(F(x)))Rotate(x);
Rotate(x);
}
pushup(x);
}
inline void access(int x){
for(int i=0;x;i=x,x=F(x))
splay(x),R(x)=i,pushup(x);
}
inline void reverse(int x){
access(x),splay(x),T[x].rev^=1;
}
inline int query(int x,int y){
reverse(x),access(y),splay(y);
return T[y].mx;
}
inline void modify(int x,int v){
access(x),splay(x),T[x].v=v,pushup(x);
}
}t;
char s[10];
void dfs(int u,int fa){
for(int i=Begin[u];i;i=Next[i]){
int v=to[i];
if(v==fa)continue;
t.T[v].fa=u;
dfs(v,u);
}
}
inline void add(int x,int y){
to[++e]=y;Next[e]=Begin[x],Begin[x]=e;
}
int main(){
int T;
read(T);
while(T--){
t.clear();Set(Begin,0),e=0;
read(n);
For(i,1,n-1){
int u,v,w;
read(u),read(v),read(w);
add(u,i+n),add(i+n,u),add(i+n,v),add(v,i+n);
t.modify(i+n,w);
}
dfs(1,0);
while(scanf("%s",s)!=EOF&&s[0]!='D'){
int x,y;
read(x),read(y);
if(s[0]=='C')t.modify(x+n,y);
else printf("%d\n",t.query(x,y));
}
}
return 0;
}
树剖(200ms 用了zkw线段树,然后vjudge上就Rank1了):
#include
#include
#include
#include
#include
#include
#include
#define For(i,j,k) for(register int i=(j);i<=(int)k;i++)
#define Forr(i,j,k) for(register int i=(j);i>=(int)k;i--)
#define Rep(i,u) for(register int i=Begin[(u)],v=to[i];i;i=Next[i],v=to[i])
#define Set(a,b) memset((a),b,sizeof(a))
using namespace std;
const int N=10010,E=20010;
int Begin[N],Next[E],to[E],fa[N],siz[N],son[N],dep[N],w[N],e=1,top[N],cnt,n;
int d[N][3];
void read(int &x){
x=0;char c=getchar();int f(0);
while(c<'0'||c>'9'){c=getchar();if(c=='-')f=1;}
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();if(f)x=-x;
}
inline void add(int x,int y){to[++e]=y,Next[e]=Begin[x],Begin[x]=e;}
struct zkwtree{
int T[N<<2],M;
inline void clear(){Set(T,0);}
inline void pushup(int x){T[x]=max(T[x<<1],T[x<<1|1]);}
void Build(){for(M=1;M<=n+1;M<<=1);}
void add(int x,int v){for(T[x+=M]=v,x>>=1;x;x>>=1)pushup(x);}
int query(int s,int t){
int ret=-0x3f3f3f3f;
for(s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1){
if(~s&1)ret=max(ret,T[s^1]);
if(t&1)ret=max(ret,T[t^1]);
}
return ret;
}
}t;
void dfs1(int u,int d){
siz[u]=1;dep[u]=d;
Rep(i,u)
if(fa[u]!=v){
fa[v]=u,dfs1(v,d+1),siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs2(int u,int tp){
top[u]=tp,w[u]=++cnt;
if(son[u])dfs2(son[u],top[u]);
Rep(i,u)
if(son[u]!=v&&fa[u]!=v)
dfs2(v,v);
}
void init(){
read(n);
Set(son,0),Set(Begin,0),Set(fa,0),e=1,cnt=0;
For(i,1,n-1){
read(d[i][0]),read(d[i][1]),read(d[i][2]);
add(d[i][0],d[i][1]),add(d[i][1],d[i][0]);
}
dfs1(1,1);dfs2(1,1);
t.clear();
t.Build();
For(i,1,n-1){
if(dep[d[i][0]]>dep[d[i][1]])swap(d[i][0],d[i][1]);
t.add(w[d[i][1]],d[i][2]);
}
}
int Max(int x,int y){
int tmp=-0x3f3f3f3f;
for(;top[x]!=top[y];){
if(dep[top[x]]if (x==y)return tmp;
if (dep[x]>dep[y])swap(x,y);
return max(tmp,t.query(w[x]+1,w[y]));
}
void solve(){
char s[10];
while(scanf("%s",s)!=EOF){
int x,y;
if (s[0]=='D')break;
read(x),read(y);
if (s[0]!='Q')t.add(w[d[x][1]],y);
else printf("%d\n",Max(x,y));
}
}
int main(){
int _;
for(read(_);_;_--){
init();
solve();
}
return 0;
}
给定一棵N(N <= 100000)个节点的树,边有权值,一开始每个节点全白,要求支持:
1.给某个节点反色(黑->白 白->黑)
2.查询最远两白点距离(特别的,只有一个白点答案为0)
边权LCT维护子树信息,pushup时注意讨论。
对于一个节点维护这样几个值:
1.一个mutiset维护以该节点为根的子树中所有节点和它的最大,次大距离
2.一个mutiset维护以该节点为根的子树中最远两白点的路径长度
3.以该点为根的辅助树中离在对应的实际的树上最上面节点(其实就是辅助树上最左节点)最远白点距离
4..以该点为根的辅助树中离在对应的实际的树上最下面节点(其实就是辅助树上最右节点)最远白点距离
最后该节点为根的子树中的答案就可以通过上面的值合并出来
在每次反色时更新答案即可
LCT(440ms)
#include
#define For(i,j,k) for(int i=(j);i<=(int)k;i++)
#define Forr(i,j,k) for(int i=(j);i>=(int)k;i--)
#define Set(a,b) memset(a,b,sizeof(a))
#define Rep(i,u) for(int i=Begin[u],v=to[i];i;i=Next[i],v=to[i])
#define L(i) (T[i].s[0])
#define R(i) (T[i].s[1])
#define F(i) (T[i].fa)
#define lmx(i) (T[i].lmx)
#define rmx(i) (T[i].rmx)
#define mx(i) (T[i].mx)
#define Loc(i) (R(F(i))==i)
#define S(i) (T[i].sum)
using namespace std;
const int N=200010 ,INF=0x3f3f3f3f;
inline void read(int &x){
x=0;char c=getchar();int f(0);
while(c<'0'||c>'9')f|=(c=='-'),c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
if(f)x=-x;
}
int n,m,e,Begin[N>>1],Next[N],to[N],w[N],ans;
inline void add(int x,int y,int z){
to[++e]=y,Next[e]=Begin[x],Begin[x]=e,w[e]=z;
}
inline int fir(multiset<int> &s){return s.size()?*s.rbegin():-INF;}
inline int sec(multiset<int> &s){return s.size()>1?*(++s.rbegin()):-INF;}
struct node{
int s[2],lmx,rmx,mx,sum,len,w,fa;
multiset<int>chain,path;
};
struct LCT{
node T[N];
inline void init(){
For(i,0,n)lmx(i)=rmx(i)=mx(i)=-INF;
}
inline void pushup(int x){
S(x)=S(L(x))+S(R(x))+T[x].len;
int cha=max(T[x].w,fir(T[x].chain));
int l=max(cha,rmx(L(x))+T[x].len);
int r=max(cha,lmx(R(x)));
lmx(x)=max(lmx(L(x)),S(L(x))+T[x].len+r);
rmx(x)=max(rmx(R(x)),S(R(x))+l);
mx(x)=max(mx(L(x)),mx(R(x)));
mx(x)=max(mx(x),fir(T[x].chain)+sec(T[x].chain));
mx(x)=max(mx(x),fir(T[x].path));
mx(x)=max(mx(x),max(rmx(L(x))+T[x].len+r,lmx(R(x))+l));
if(T[x].w==0)mx(x)=max(mx(x),max(fir(T[x].chain),0));
}
inline bool isrt(int x){
return R(F(x))!=x&&L(F(x))!=x;
}
inline void Rotate(int x){
int A=F(x),B=F(A),l=Loc(x),r=l^1,d=Loc(A);
if(!isrt(A))T[B].s[d]=x;F(x)=B;
F(A)=x,F(T[x].s[r])=A,T[A].s[l]=T[x].s[r],T[x].s[r]=A;
pushup(A);
}
inline void splay(int x){
while(!isrt(x)){
int y=F(x);
if(isrt(y))Rotate(x);
else if(Loc(x)^Loc(y))Rotate(x),Rotate(x);
else Rotate(y),Rotate(x);
}
pushup(x);
}
inline void access(int x){
for(int i=0;x;i=x,x=F(x)){
splay(x);
if(R(x))T[x].chain.insert(lmx(R(x))),T[x].path.insert(mx(R(x)));
if(i)T[x].chain.erase(T[x].chain.find(lmx(i))),T[x].path.erase(T[x].path.find(mx(i)));
R(x)=i,pushup(x);
}
}
inline void modify(int x){
access(x);splay(x),T[x].w=(T[x].w==0)?-INF:0;pushup(x);
ans=mx(x);
}
}t;
void dfs(int u){
Rep(i,u)
if(t.T[u].fa!=v)
t.T[v].fa=u,t.T[v].len=w[i],dfs(v),
t.T[u].chain.insert(t.T[v].lmx),t.T[u].path.insert(t.T[v].mx);
t.pushup(u);
}
char s[10];
int main(){
read(n);t.init();
For(i,1,n-1){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w),add(v,u,w);
}
dfs(1);ans=t.T[1].mx;
read(m);
while(m--){
int x;
scanf("%s",s);
if(s[0]=='A'){
if(ans<0)puts("They have disappeared.");
else printf("%d\n",ans);
}else read(x),t.modify(x);
}
return 0;
}
Qtree4弱化版
给定一棵N(N <= 100000)个节点的树,边权为1,一开始每个节点全黑,要求支持:
1.给某个节点反色(黑->白 白->黑)
2.查询最远离v点最近白点距离(特别的,v是白点时答案为0)
与QTREE4类似
最大值变最小值
答案不合并
边权是1
LCT(450ms)
#include
#include
#include
#include
#include
#include
#define For(i,j,k) for(int i=(j);i<=(int)k;i++)
#define Forr(i,j,k) for(int i=(j);i>=(int)k;i--)
#define Rep(i,u) for(int i=Begin[u],v=to[i];i;i=Next[i],v=to[i])
#define L(i) (T[i].s[0])
#define R(i) (T[i].s[1])
#define F(i) (T[i].fa)
#define lmi(i) (T[i].lmi)
#define rmi(i) (T[i].rmi)
#define mi(i) (T[i].mi)
#define S(i) (T[i].sum)
#define Loc(i) (R(F(i))==i)
#define getchar getchar_unlocked//卡常数
using namespace std;
const int N=200010,INF=100000000;
inline int fir(multiset<int> &s){return s.size()>0?(*s.begin()):INF;}
inline void read(int &x){
x=0;char c=getchar();int f(0);
while(c<'0'||c>'9')f|=(c=='-'),c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
if(f)x=-x;
}
int Begin[N],to[N],Next[N],e,n,m;
inline void add(int x,int y){
to[++e]=y,Next[e]=Begin[x],Begin[x]=e;
}
struct node{
int s[2],lmi,rmi,fa,sum,w,mi;
multiset<int>chain;
};
struct LCT{
node T[N];
inline void init(){
For(i,0,n)lmi(i)=T[i].w=rmi(i)=INF,T[i].chain.clear();
}
inline void pushup(int x){
S(x)=S(L(x))+S(R(x))+1;
int cha=min(T[x].w,fir(T[x].chain));
int l=min(cha,rmi(L(x))+1),r=min(cha,lmi(R(x)));
lmi(x)=min(lmi(L(x)),S(L(x))+1+r);
rmi(x)=min(rmi(R(x)),S(R(x))+l);
mi(x)=min(l,r);
}
inline bool isrt(int x){
return R(F(x))!=x&&L(F(x))!=x;
}
inline void Rotate(int x){
int A=F(x),B=F(A),l=Loc(x),r=l^1,d=Loc(A);
if(!isrt(A))T[B].s[d]=x;F(x)=B;
F(A)=x,F(T[x].s[r])=A,T[A].s[l]=T[x].s[r],T[x].s[r]=A;
pushup(A);
}
inline void splay(int x){
while(!isrt(x)){
int y=F(x);
//For(i,0,n)print(i);puts("");
//printf("%d\n",isrt(y));
if(isrt(y))Rotate(x);
else if (Loc(y)^Loc(x))Rotate(x),Rotate(x);
else Rotate(y),Rotate(x);
}
pushup(x);
}
inline void access(int x){
for(int i=0;x;i=x,x=F(x)){
splay(x);
if(R(x))T[x].chain.insert(lmi(R(x)));
if(i)T[x].chain.erase(T[x].chain.find(lmi(i)));
R(x)=i,pushup(x);
}
}
inline void modify(int x){
access(x);splay(x);
T[x].w=(T[x].w==0)?INF:0;
pushup(x);
}
inline void query(int x){
access(x);splay(x);
printf("%d\n",mi(x)==INF?-1:mi(x));
}
}t;
void dfs(int u){
Rep(i,u)
if(t.T[u].fa!=v){
t.T[v].fa=u,dfs(v);
t.T[u].chain.insert(t.T[v].lmi);
}
t.pushup(u);
}
int main(){
int u,v;
read(n);t.init();
For(i,1,n-1){
read(u),read(v);
add(u,v),add(v,u);
}
dfs(1);
read(m);
while(m--){
read(u),read(v);
if(u==0)t.modify(v);
else t.query(v);
}
return 0;
}
给定一棵N(N <= 100000)个节点的树,一开始每个节点全黑,要求支持:
1.反色
2.查询与之有联系的点的个数(两点有联系当且仅当两点路径上所有点颜色相同)
维护两棵LCT,一棵黑树森林一棵白树森林
反色时在原来颜色的树中断开与父亲节点的连边,在更改后颜色树中连接与父亲节点的连边,然后查询就直接查询该点所在树大小即可,注意根节点的判断
#include
#include
#include
#include
#include
#include
#define For(i,j,k) for(register int i=(j);i<=(int)k;i++)
#define Forr(i,j,k) for(register int i=(j);i>=(int)k;i--)
#define Rep(i,u) for(register int i=Begin[u],v=to[i];i;i=Next[i],v=to[i])
#define Set(a,b) memset(a,b,sizeof(a))
#define L(i) (T[i].s[0])
#define R(i) (T[i].s[1])
#define S(i) (T[i].sum)
#define ss(i) (T[i].ss)
#define F(i) (T[i].fa)
#define Loc(i) (R(F(i))==i)
#define getchar getchar_unlocked
using namespace std;
const int N=100001,INF=0x3f3f3f3f;
inline void read(int &x){
x=0;char c=getchar();int f(0);
while(c<'0'||c>'9')f|=(c=='-'),c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
if(f)x=-x;
}
int Begin[N],Next[N<<1],to[N<<1],e,col[N],fa[N];
inline void add(int x,int y){
to[++e]=y,Next[e]=Begin[x],Begin[x]=e;
}
struct node {
int s[2],sum,fa,ss;
};
struct LCT{
node T[N];
inline void pushup(int x){
S(x)=S(L(x))+S(R(x))+ss(x)+1;
}
inline bool isrt(int x){
return R(F(x))!=x&&L(F(x))!=x;
}
inline void Rotate(int x){
int A=F(x),B=F(A),l=Loc(x),r=l^1,d=Loc(A);
if(!isrt(A))T[B].s[d]=x;F(x)=B;
F(A)=x,F(T[x].s[r])=A,T[A].s[l]=T[x].s[r],T[x].s[r]=A;
pushup(A);
}
inline void splay(int x){
while(!isrt(x)){
int y=F(x);
if(!isrt(y))Rotate(x);
Rotate(x);
}
pushup(x);
}
inline void access(int x){
for(int i=0;x;i=x,x=F(x)){
splay(x);
if(R(x))ss(x)+=S(R(x));
if(i)ss(x)-=S(i);
R(x)=i;pushup(x);
}
}
inline void cut(int x){
access(x),splay(x);
F(L(x))=0,L(x)=0,pushup(x);
}
inline void link(int x,int y){
access(y),splay(y);splay(x);
F(x)=y,R(y)=x,pushup(y);
}
inline int findrt(int x){
access(x),splay(x);
while(L(x))x=L(x);
return x;
}
inline void query(int x){
int c=col[x];
x=findrt(x);
splay(x);
printf("%d\n",col[x]==c?S(x):S(R(x)));
}
}t[2];
void dfs(int u){
Rep(i,u)
if(fa[u]!=v){
fa[v]=u,t[1].T[v].fa=u,dfs(v);
t[1].T[u].ss+=t[1].T[v].sum;
}
t[1].pushup(u);
}
int n,m;
int main(){
int tp,u;
read(n);
For(i,1,n-1){
int u,v;
read(u),read(v);
add(u,v),add(v,u);col[i]=1;
}col[n]=1;
dfs(1);
read(m);
while(m--){
read(tp),read(u);
if(tp==0)
t[col[u]].query(u);
else{
if(fa[u])t[col[u]].cut(u),t[col[u]^1].link(u,fa[u]);
col[u]^=1;
}
}
return 0;
}
给定一棵N(N <= 100000)个节点的树,一开始每个节点全黑,要求支持:
1.反色
2.查询与之有联系的点中的最大权值(两点有联系当且仅当两点路径上所有点颜色相同)
3.修改u的点权
与QTREE6类似
多加一个mutiset就好了
#include
#include
#include
#include
#include
#include
#define L(i) (T[i].s[0])
#define R(i) (T[i].s[1])
#define F(i) (T[i].fa)
#define Mx(i) (T[i].Mx)
#define W(i) (T[i].w)
#define Loc(i) (R(F(i))==i)
#define For(i,j,k) for(int i=(j);i<=(int)k;i++)
#define Forr(i,j,k) for(int i=(j);i>=(int)k;i--)
#define Set(a,b) memset(a,b,sizeof(a));
#define Rep(i,u) for(int i=Begin[u],v=to[i];i;i=Next[i],v=to[i])
#define getchar getchar_unlocked
using namespace std;
const int N=100100,INF=0x3f3f3f3f;
inline int fir(multiset<int>&s){return s.size()?*s.rbegin():-INF;}
inline void read(int &x){
x=0;char c=getchar();int f(0);
while(c<'0'||c>'9')f|=(c=='-'),c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
if(f)x=-x;
}
int Begin[N],to[N<<1],Next[N<<1],e,fa[N],col[N];
inline void add(int x,int y){
to[++e]=y,Next[e]=Begin[x],Begin[x]=e;
}
struct node{
int s[2],fa,w,Mx;
multiset<int>mx;
};
struct LCT{
node T[N];
inline void pushup(int x){
Mx(x)=max(W(x),fir(T[x].mx));
if(L(x))Mx(x)=max(Mx(x),Mx(L(x)));
if(R(x))Mx(x)=max(Mx(x),Mx(R(x)));
}
inline bool isrt(int x){
return R(F(x))!=x&&L(F(x))!=x;
}
inline void Rotate(int x){
int A=F(x),B=F(A),l=Loc(x),r=l^1,d=Loc(A);
if(!isrt(A))T[B].s[d]=x;F(x)=B;
F(A)=x,F(T[x].s[r])=A,T[A].s[l]=T[x].s[r],T[x].s[r]=A;
pushup(A);
}
inline void splay(int x){
while(!isrt(x)){
if(!isrt(F(x)))Rotate(x);
Rotate(x);
}
pushup(x);
}
inline void access(int x){
for(int i=0;x;i=x,x=F(x)){
splay(x);
if(R(x))T[x].mx.insert(Mx(R(x)));
if(i)T[x].mx.erase(T[x].mx.find(Mx(i)));
R(x)=i,pushup(x);
}
}
inline void link(int x,int y){
access(y),splay(y),splay(x);
F(x)=y,R(y)=x,pushup(y);
}
inline void cut(int x){
access(x),splay(x),L(x)=F(L(x))=0,pushup(x);
}
inline int findrt(int x){
access(x),splay(x);
while(L(x))x=L(x);
return x;
}
inline void query(int x){
int c=col[x];
x=findrt(x);splay(x);
printf("%d\n",c==col[x]?Mx(x):Mx(R(x)));
}
inline void modify(int x,int val){
access(x),splay(x);
W(x)=val;pushup(x);
}
}t[2];
int n,m;
void dfs(int u){
Rep(i,u)
if(fa[u]!=v){
fa[v]=t[col[v]].T[v].fa=u,dfs(v);
t[col[v]].T[u].mx.insert(t[col[v]].T[v].Mx);
}
t[0].pushup(u);t[1].pushup(u);
}
int main(){
read(n);
For(i,1,n-1){
int u,v;
read(u),read(v);
add(u,v),add(v,u);
}
For(i,1,n)read(col[i]);
For(i,1,n)read(t[0].T[i].w),t[1].T[i].w=t[0].T[i].w;
dfs(1);
read(m);
while(m--){
int tp,u,v;
read(tp),read(u);
if(tp==0)t[col[u]].query(u);
else if(tp==1){
if(fa[u])t[col[u]].cut(u),t[col[u]^1].link(u,fa[u]);
col[u]^=1;
}else {
read(v);
t[0].modify(u,v),t[1].modify(u,v);
}
}
return 0;
}
注意不要换根,因为会改变树形态