直接开每个颜色开一个线段树维护直径,再对颜色开颗线段树即可
#include
using namespace std;
#define cs const
#define pb push_back
#define pii pair
#define fi first
#define se second
#define ll long long
#define bg begin
namespace IO{
cs int rlen=1<<22|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
(ib==ob)&&(ob==(ib=ibuf)+fread(ibuf,1,rlen,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool f=0;
while(!isdigit(ch))f=ch=='-',ch=gc();
while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
return f?-res:res;
}
}
using IO::read;
template<typename tp>inline void chemx(tp &a,tp b){(a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){(a>b)?(a=b):0;}
cs int N=100005;
char xxx;
int in[N],dfn,st[19][N<<1],dep[N],fa[N],lg[N<<1];
int adj[N],nxt[N<<1],to[N<<1],ecnt;
void addedge(int u,int v){
nxt[++ecnt]=adj[u],adj[u]=ecnt,to[ecnt]=v;
}
inline int MIN(int x,int y){return in[x]<in[y]?x:y;}
inline int Lca(int x,int y){
x=in[x],y=in[y];
if(x>y)swap(x,y);
int t=lg[y-x+1];
return MIN(st[t][x],st[t][y-(1<<t)+1]);
}
inline int dis(int x,int y){
// assert(x!=0),assert(y!=0);
return dep[x]+dep[y]-2*dep[Lca(x,y)];
}
void dfs(int u){
st[0][++dfn]=u,in[u]=dfn;
for(int e=adj[u],v;e;e=nxt[e])if((v=to[e])!=fa[u]){
fa[v]=u,dep[v]=dep[u]+1,dfs(v);
st[0][++dfn]=u;
}
}
void buildst(){
for(int i=2;i<=dfn;i++)lg[i]=lg[i>>1]+1;
for(int i=1;(1<<i)<=dfn;i++)
for(int j=1;j+(1<<i)-1<=dfn;j++)
st[i][j]=MIN(st[i-1][j],st[i-1][j+(1<<(i-1))]);
}
struct node{
int x,y;
node(int _x=0,int _y=0):x(_x),y(_y){}
friend inline node operator +(cs node &a,cs node &b){
if(!a.x)return b;if(!b.x)return a;int mx=-1,t,t1=0,t2=0;
if((t=dis(a.x,a.y))>mx)mx=t,t1=a.x,t2=a.y;
if((t=dis(a.x,b.x))>mx)mx=t,t1=a.x,t2=b.x;
if((t=dis(a.x,b.y))>mx)mx=t,t1=a.x,t2=b.y;
if((t=dis(a.y,b.x))>mx)mx=t,t1=a.y,t2=b.x;
if((t=dis(a.y,b.y))>mx)mx=t,t1=a.y,t2=b.y;
if((t=dis(b.x,b.y))>mx)mx=t,t1=b.x,t2=b.y;
assert(mx>=0);
return node(t1,t2);
}
};
int n,m,q,rt[N];
namespace seg2{
#define mid ((l+r)>>1)
cs int N=::N*50;
node s[N];int lc[N],rc[N],tot;
void insert(int &u,int l,int r,int p){
if(!u)u=++tot;
if(l==r){
s[u]=node(p,p);return;
}
if(p<=mid)insert(lc[u],l,mid,p);
else insert(rc[u],mid+1,r,p);
s[u]=s[lc[u]]+s[rc[u]];
}
void delet(int &u,int l,int r,int p){
if(l==r){s[u]=node(0,0);return;}
if(p<=mid)delet(lc[u],l,mid,p);
else delet(rc[u],mid+1,r,p);
s[u]=s[lc[u]]+s[rc[u]];
}
#undef mid
}
namespace seg1{
node s[N<<2];
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
void build(int u,int l,int r){
if(l==r){
s[u]=seg2::s[rt[l]];
return;
}build(lc,l,mid),build(rc,mid+1,r);
s[u]=s[lc]+s[rc];
}
void update(int u,int l,int r,int p,int k,int kd){
if(l==r){
if(kd==0)seg2::delet(rt[l],1,n,k);
else seg2::insert(rt[l],1,n,k);
s[u]=seg2::s[rt[l]];return;
}
if(p<=mid)update(lc,l,mid,p,k,kd);
else update(rc,mid+1,r,p,k,kd);
s[u]=s[lc]+s[rc];
}
node query(int u,int l,int r,int st,int des){
if(st<=l&&r<=des)return s[u];
if(des<=mid)return query(lc,l,mid,st,des);
if(mid<st)return query(rc,mid+1,r,st,des);
return query(lc,l,mid,st,des)+query(rc,mid+1,r,st,des);
}
#undef lc
#undef rc
#undef mid
}
char yyy;
int col[N];
int main(){
n=read(),m=read(),q=read();
for(int i=1;i<=n;i++)col[i]=read();
for(int i=1;i<n;i++){
int u=read(),v=read();
addedge(u,v),addedge(v,u);
}dep[1]=1,dfs(1),buildst();
for(int i=1;i<=n;i++)seg2::insert(rt[col[i]],1,n,i);
seg1::build(1,1,m);
for(int i=1;i<=q;i++){
int op=read(),x=read(),y=read();
if(op==1){
seg1::update(1,1,m,col[x],x,0);
col[x]=y;
seg1::update(1,1,m,col[x],x,1);
}
else{
node f=seg1::query(1,1,m,x,y);
if(!f.x)cout<<0<<'\n';
else cout<<dis(f.x,f.y)<<'\n';
}
}return 0;
}
首先可以发现 s g sg sg就是 m a x d e p maxdep maxdep
首先我的垃圾做法是考虑提出直径,然后大力分类讨论
#include
using namespace std;
#define cs const
#define pb push_back
#define pii pair
#define fi first
#define se second
#define ll long long
#define bg begin
namespace IO{
cs int rlen=1<<22|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool f=0;
while(!isdigit(ch))f=ch=='-',ch=gc();
while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
return f?-res:res;
}
}
using IO::read;
template<typename tp>inline void chemx(tp &a,tp b){(a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){(a>b)?(a=b):0;}
cs int N=2e5+5;
char xxx;
inline pii operator ^(cs pii &a,cs pii &b){return pii(a.fi^b.fi,a.se^b.se);}
struct Seg{
int n,coef[N<<2],tag[N<<2],s[N<<2];
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
void build(int u,int l,int r,int *vl){
if(l==r){tag[u]=1,s[u]=coef[u]=vl[l];return;}
build(lc,l,mid,vl),build(rc,mid+1,r,vl);
s[u]=coef[u]=coef[lc]^coef[rc];
}
void init(int _n,int *vl){
n=_n;
if(!n)return;
build(1,1,n,vl);
}
int st,des;
void upd(int u,int l,int r){
if(st<=l&&r<=des){tag[u]^=1;s[u]^=coef[u];return;}
if(st<=mid)upd(lc,l,mid);
if(mid<des)upd(rc,mid+1,r);
s[u]=s[lc]^s[rc]^(tag[u]?coef[u]:0);
}
void update(int l,int r){if(!n)return;
st=l,des=r;upd(1,1,n);
}
pii qy(int u,int l,int r){
if(st<=l&&r<=des)return pii(s[u],coef[u]);
pii now;
if(st<=mid)now=now^qy(lc,l,mid);
if(mid<des)now=now^qy(rc,mid+1,r);
if(tag[u])now.fi^=now.se;return now;
}
int query(int l,int r){if(!n)return 0;
st=l,des=r;pii x=qy(1,1,n);
return x.fi;
}
int fin(int u,int l,int r,int p){
if(l==r)return tag[u];
if(p<=mid)return fin(lc,l,mid,p)^tag[u];
return fin(rc,mid+1,r,p)^tag[u];
}
int find(int p){
if(!n)return 0;
return fin(1,1,n,p);
}
#undef lc
#undef rc
#undef mid
}c1,c2,t1,t2;
// c1->left c2->right t1->sub t2->other
int up[N],rt[N],isc[N],a[N],nrt,n,m;
int chain[N],len,mxlen[N],mxup[N];
int dep[N],fa[N],top[N],in[N],out[N],siz[N],son[N],idx[N],dfn;
int adj[N],nxt[N<<1],to[N<<1],ecnt;
inline void addedge(int u,int v){
nxt[++ecnt]=adj[u],adj[u]=ecnt,to[ecnt]=v;
}
int dfs(int u,int udep,int urt,int rtt){
up[u]=urt,rt[u]=rtt,mxup[u]=udep,siz[u]=1;
for(int e=adj[u],v;e;e=nxt[e])if((v=to[e])!=fa[u]){
if(isc[v])continue;
fa[v]=u,dep[v]=dep[u]+1;
chemx(mxlen[u],dfs(v,udep+1,urt,rtt)+1);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}return mxlen[u];
}
void dfs2(int u,int tp){
top[u]=tp;in[u]=++dfn,idx[dfn]=u;
if(son[u])dfs2(son[u],tp);
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(v==fa[u]||v==son[u]||isc[v])continue;
dfs2(v,v);
}out[u]=dfn;
}
int mxdp,mdes,pre[N],mst;
pii qr[N];int cnt;
void updatetree(int l,int r){
if(l>r)return;
t1.update(l,r),t2.update(l,r);
}
int find(int u,int p){
int v=0;
while(top[u]!=top[p])v=top[u],u=fa[top[u]];
if(u==p)return v;
return son[p];
}
void updatechain(int l,int r){
if(l>r)return;
c1.update(l,r),c2.update(l,r);
}
void updatepath(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
updatetree(in[top[u]],in[u]);
u=fa[top[u]];
}if(dep[u]>dep[v])swap(u,v);
updatetree(in[u],in[v]);
}
int get(int u){
cnt=0;
while(u){
qr[++cnt]=pii(in[top[u]],in[u]);
u=fa[top[u]];
}
reverse(qr+1,qr+cnt+1);
int res=0;
for(int i=1;i<=cnt;i++){
res^=t2.query(qr[i].fi,qr[i].se);
if(qr[i-1].se+1<=qr[i].fi-1)res^=t1.query(qr[i-1].se+1,qr[i].fi-1);
}
if(qr[cnt].se<dfn)res^=t1.query(qr[cnt].se+1,dfn);
return res;
}
void dfss(int u,int fa,int dep){
if(dep>mxdp)mxdp=dep,mst=u;
for(int e=adj[u],v;e;e=nxt[e])if((v=to[e])!=fa){
dfss(v,u,dep+1);
}
}
void dfst(int u,int dep){
if(dep>mxdp)mxdp=dep,mst=u;
for(int e=adj[u],v;e;e=nxt[e])if((v=to[e])!=pre[u]){
pre[v]=u,dfst(v,dep+1);
}
}
char yyy;
int main(){
#ifdef Stargazer
freopen("lx.in","r",stdin);
freopen("my.out","w",stdout);
#endif
n=read(),m=read();
for(int i=1;i<n;i++){
int u=read(),v=read();
addedge(u,v),addedge(v,u);
}
dfss(1,0,0),mxdp=0,mdes=mst,dfst(mst,0);
int u=mst;
while(u!=mdes){
chain[++len]=u,u=pre[u];
}chain[++len]=mdes;
for(int i=1;i<=len;i++)a[i]=i-1;
c1.init(len,a);
for(int i=1;i<=len;i++)a[i]=len-i;
c2.init(len,a);
for(int i=1;i<=len;i++)isc[chain[i]]=1;
for(int i=1;i<=len;i++){int u=chain[i];up[u]=i;
in[u]=dfn+1;
for(int e=adj[u],v;e;e=nxt[e])if(!isc[v=to[e]]){
dfs(v,max(i-1,len-i)+1,i,v),dfs2(v,v);
}
out[u]=dfn;
}
for(int i=1;i<=dfn;i++)a[i]=mxlen[idx[i]];
t1.init(dfn,a);
for(int i=1;i<=dfn;i++)a[i]=mxup[idx[i]];
t2.init(dfn,a);nrt=1;
while(m--){
int op=read();
if(op==1){
int u=read(),v=read();
if(!isc[u]&&!isc[v]&&rt[u]==rt[v]){
updatepath(u,v);
}
else{
if(!isc[u])updatepath(u,rt[u]);
if(!isc[v])updatepath(v,rt[v]);
updatechain(min(up[u],up[v]),max(up[u],up[v]));
}
}
else{
int u=read();
if(u==nrt){
updatetree(1,dfn),updatechain(1,len);
}
else if(!isc[nrt]){
if(in[u]<=in[nrt]&&in[nrt]<=out[u]&&!isc[u]){
updatechain(1,len);
int p=find(nrt,u);
updatetree(1,in[p]-1);
updatetree(out[p]+1,dfn);
}
else if((in[nrt]<=in[u]&&in[u]<=out[nrt])&&!isc[u]){
updatetree(in[u],out[u]);
}
else if(!isc[u]){
updatetree(in[u],out[u]);
}
else{
assert(isc[u]);
int id=up[u];
if(id==up[nrt]){
updatechain(1,len);
updatetree(1,in[rt[nrt]]-1);
updatetree(out[rt[nrt]]+1,dfn);
}
else{
if(id<up[nrt]){
updatechain(1,id);
updatetree(1,out[chain[id]]);
}
else{
updatechain(id,len);
updatetree(in[chain[id]],dfn);
}
}
}
}
else{
if(!isc[u]){
updatetree(in[u],out[u]);
}
else{
int id=up[u];
if(id<up[nrt]){
updatechain(1,id);
updatetree(1,out[chain[id]]);
}
else{
updatechain(id,len);
updatetree(in[chain[id]],dfn);
}
}
}
}
int x=read();
nrt=x;int res=max(up[x]-1,len-up[x])*(c1.find(up[x])&1);
if(isc[x]){
res^=t1.query(1,dfn);
if(up[x]>1)res^=c1.query(1,up[x]-1);
if(up[x]<len)res^=c2.query(up[x]+1,len);
}
else{
res^=get(x);
if(up[x]>1)res^=c1.query(1,up[x]-1);
if(up[x]<len)res^=c2.query(up[x]+1,len);
}cout<<res<<'\n';
}
}
s t d std std是考虑直径中点为根
维护两个方向的 m x d e p mxdep mxdep
这样就只是把一条链的权值换一下,树剖即可
仲爺教育我的神仙方法
直接把1作为根
不同的只是1到当前根的路径
只需要重剖时链权值变成重儿子为根的 d e p dep dep
跳轻链的时候另外算一下即可
考虑设
f [ i ] [ j ] [ 0 / 1 ] f[i][j][0/1] f[i][j][0/1]
表示前 i i i站, j j j轮,每辆车都满,初始人数为 0 / 1 ∗ a i 0/1*a_i 0/1∗ai的最小车数
g g g表示在 s : 31 s:31 s:31时,除 p p p以外都空的最短车数
考虑上一次接到p的人的时间
如果没有, f [ i ] [ j ] = f [ i − 1 ] [ j ] f[i][j]=f[i-1][j] f[i][j]=f[i−1][j]
设 v a l = ⌈ 0 / 1 ∗ s a i − 1 + j ∗ s b i − 1 k ⌉ val=\lceil\frac{0/1*sa_{i-1}+j*sb_{i-1}}{k}\rceil val=⌈k0/1∗sai−1+j∗sbi−1⌉
如果 v a l ∗ k ≤ k ∗ s a i + j ∗ s b i , g [ i ] [ j ] [ k ] = v a l val*k\le k*sa_i+j*sb_i,g[i][j][k]=val val∗k≤k∗sai+j∗sbi,g[i][j][k]=val
如果有,设为 p p p
那么决策是 r r r前有个数量,然后派若干辆保证之后不炸,这次再派若干辆
那么首先派 g [ i ] [ p ] [ k ] g[i][p][k] g[i][p][k],此 p p p时 i i i剩 m = k ∗ s a i + p ∗ s b i − k ∗ g [ i ] [ p ] [ k ] m=k*sa_i+p*sb_i-k*g[i][p][k] m=k∗sai+p∗sbi−k∗g[i][p][k]
此时需要派 x = ( max ( m + ( j − p ) ∗ b i − c i , 0 ) + k − 1 ) / k x=(\max({m+(j-p)*b_i-c_i,0})+k-1)/k x=(max(m+(j−p)∗bi−ci,0)+k−1)/k辆
当然如果 x ∗ k > m x*k>m x∗k>m,不合法
此时前面都不剩了,且还需要坚持 j − p j-p j−p轮
f [ i ] [ j ] [ k ] = g [ i ] [ p ] [ k ] + x + f [ i − 1 ] [ j − p ] [ 0 ] f[i][j][k]=g[i][p][k]+x+f[i-1][j-p][0] f[i][j][k]=g[i][p][k]+x+f[i−1][j−p][0]
v l = ( ( j − p ) ∗ s b i − 1 + k − 1 ) / k vl=((j-p)*sb_{i-1}+k-1)/k vl=((j−p)∗sbi−1+k−1)/k
如果 v l ∗ k ≤ s b i ∗ ( j − p ) + m − x ∗ k vl*k\le sb_i*(j-p)+m-x*k vl∗k≤sbi∗(j−p)+m−x∗k
那么 g [ i ] [ j ] [ k ] = g [ i ] [ p ] [ k ] + x + v l g[i][j][k]=g[i][p][k]+x+vl g[i][j][k]=g[i][p][k]+x+vl
#include
using namespace std;
#define cs const
#define pb push_back
#define pii pair
#define fi first
#define se second
#define ll long long
#define bg begin
namespace IO{
cs int rlen=1<<22|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool f=0;
while(!isdigit(ch))f=ch=='-',ch=gc();
while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
return f?-res:res;
}
}
using IO::read;
template<typename tp>inline void chemx(tp &a,tp b){(a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){(a>b)?(a=b):0;}
cs int N=306;
ll f[N][N][2],g[N][N][2],sa[N],sb[N],sc[N],a[N],b[N],c[N];
cs ll inf=1e17;
int n,t,K;
int main(){
n=read(),t=read(),K=read();
for(int i=1;i<=n;i++)a[i]=read(),b[i]=read(),c[i]=read();
a[++n]=inf,b[n]=0,c[n]=inf;
for(int i=1;i<=n;i++)sa[i]=sa[i-1]+a[i],sb[i]=sb[i-1]+b[i],sc[i]=sc[i-1]+c[i];
for(int i=1;i<=n;i++)memset(f[i],127/3,sizeof(f[i])),memset(g[i],127/3,sizeof(g[i]));
for(int i=1;i<=n;i++)
for(int j=0;j<=t;j++)
for(int k=0;k<2;k++){
if(f[i-1][j][k]<inf&&a[i]*k+b[i]*j<=c[i]){
chemn(f[i][j][k],f[i-1][j][k]);
ll vl=(sa[i-1]*k+sb[i-1]*j+K-1)/K;
if(vl*K<=sa[i]*k+sb[i]*j)chemn(g[i][j][k],vl);
}
for(int p=0;p<j;p++)if(g[i][p][k]<inf){
ll m=sa[i]*k+p*sb[i]-g[i][p][k]*K,
x=(max(m+(j-p)*b[i]-c[i],0ll)+K-1)/K;
if(x*K>m||f[i-1][j-p][0]>=inf)continue;
chemn(f[i][j][k],g[i][p][k]+x+f[i-1][j-p][0]);
ll vl=((j-p)*sb[i-1]+K-1)/K;
if(vl*K<=sb[i]*(j-p)+m-x*k)chemn(g[i][j][k],g[i][p][k]+x+vl);
}
}cout<<f[n][t][1]<<'\n';return 0;
}