BZOJ传送门
洛谷传送门
解析:
其实就是QTREE4的弱化版,可以直接用QTREE4的解法来做。
但是这道题有优秀的 O ( n log n ) O(n\log n) O(nlogn)做法。
我们考虑利用DFS出的括号序列来处理距离。
将点的编号塞到括号序列里面,那么两个点的距离就是它们中间的括号序列的非匹配括号数。
证明因为极度弱智不想写了。
现在考虑用线段树来维护这个括号序列。
考虑如何得到横跨两个区间分界点的所有白色点对的距离最大值。
考虑区间 l l l的某个后缀 ( a 1 , b 1 ) (a1,b1) (a1,b1),表示这个区间有 a 1 a1 a1个无法匹配的右括号和 b 1 b1 b1个无法匹配的左括号
同理考虑区间 r r r的某个前缀 ( a 2 , b 2 ) (a2,b2) (a2,b2)。
显然这样两个前后缀拼起来表示的距离就是 a 1 + a b s ( b 1 − a 2 ) + b 2 a1+abs(b1-a2)+b2 a1+abs(b1−a2)+b2,显然我们需要的就是 max ( a 1 + a b s ( b 1 − a 2 ) + b 2 ) \max(a1+abs(b1-a2)+b2) max(a1+abs(b1−a2)+b2)把里面的式子稍微转化一下得到: a 1 + max ( a 2 − b 1 , b 1 − a 2 ) + b 2 = max ( a 1 − b 1 + a 2 + b 2 , a 1 + b 1 − a 2 + b 2 ) a1+\max(a2-b1,b1-a2)+b2=\max(a1-b1+a2+b2,a1+b1-a2+b2) a1+max(a2−b1,b1−a2)+b2=max(a1−b1+a2+b2,a1+b1−a2+b2)
所以我们需要维护前缀的 − a + b , a + b -a+b,a+b −a+b,a+b的最大值,后缀 a − b , a + b a-b,a+b a−b,a+b的最大值。
线段树上随便做啊。
对于黑点白点只需要在线段树叶子节点处理一下这四个值就行了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline char getalpha(){
re char c;
while(!isalpha(c=gc()));return c;
}
}
using namespace IO;
using std::cout;
cs int N=1e5+5;
int n,q;
int last[N],to[N<<1],nxt[N<<1],ecnt;
inline void addedge(int u,int v){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v;
nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u;
}
int in[N*3],tot,pos[N];
void dfs(int u,int fa){
in[++tot]=-1;
in[++tot]=u;
pos[u]=tot;
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]])
if(v!=fa)dfs(v,u);
in[++tot]=-2;
}
cs int M=N*3<<2;
int a[M],b[M],l1[M],l2[M],r1[M],r2[M],dis[M];
bool col[N];
inline void init(int k,int id){
dis[k]=-1;
a[k]=b[k]=0;
l1[k]=l2[k]=r1[k]=r2[k]=-1e9;
switch(in[id]){
case -1:b[k]=1;break;
case -2:a[k]=1;break;
default:if(!col[in[id]])l1[k]=l2[k]=r1[k]=r2[k]=dis[k]=0;break;
}
}
inline void pushup(int k){
int lc=k<<1,rc=k<<1|1;
if(b[lc]>a[rc])a[k]=a[lc],b[k]=b[lc]-a[rc]+b[rc];
else b[k]=b[rc],a[k]=a[lc]+a[rc]-b[lc];
l1[k]=std::max(l1[lc],std::max(l1[rc]+a[lc]-b[lc],l2[rc]+a[lc]+b[lc]));
l2[k]=std::max(l2[lc],l2[rc]-a[lc]+b[lc]);
r1[k]=std::max(r1[rc],std::max(r1[lc]-a[rc]+b[rc],r2[lc]+a[rc]+b[rc]));
r2[k]=std::max(r2[rc],r2[lc]+a[rc]-b[rc]);
dis[k]=std::max(std::max(dis[lc],dis[rc]),std::max(r1[lc]+l2[rc],r2[lc]+l1[rc]));
}
inline void build(int k,int l,int r){
if(l==r)return init(k,l);
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
inline void modify(int k,int l,int r,cs int &pos){
if(l==r){
col[in[pos]]^=1;
init(k,pos);
return ;
}
int mid=(l+r)>>1;
if(pos<=mid)modify(k<<1,l,mid,pos);
else modify(k<<1|1,mid+1,r,pos);
pushup(k);
}
signed main(){
n=getint();
for(int re i=1;i<n;++i)addedge(getint(),getint());
dfs(1,0);
build(1,1,tot);
q=getint();
while(q--)switch(getalpha()){
case 'G':cout<<dis[1]<<"\n";break;
case 'C':modify(1,1,tot,pos[getint()]);break;
}
return 0;
}