题目链接
这题原来一直T,题解也大多是点分治括号序列等。
我是用边分治写的。
加上快读和O2,这题就过了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
#define llu unsigned ll
using namespace std;
char buffer[100001],*S,*T;
inline char Get_Char()
{
if (S==T)
{
T=(S=buffer)+fread(buffer,1,100001,stdin);
if (S==T) return EOF;
}
return *S++;
}
inline int read()
{
char c;int re=0;
for(c=Get_Char();c<'0'||c>'9';c=Get_Char());
while(c>='0'&&c<='9') re=re*10+(c-'0'),c=Get_Char();
return re;
}
inline char read_charA()
{
char c;
for(c=Get_Char();c<'A'||c>'Z';c=Get_Char());
return c;
}
const ll lnf=0x3f3f3f3f3f3f3f3f;
const int maxn=200100;
int head[maxn],ver[maxn*20],edge[maxn*20],nt[maxn*20];
int Head[maxn],Ver[maxn<<1],Edge[maxn<<1],Nt[maxn<<1],tail[maxn],pre[maxn*20];
int d[maxn];
bool ha[maxn];
int nown,n,tot,TOT,root,midedge,maxx,cnt;
void init(void)
{
memset(head,0,sizeof(head));
tot=1;
}
void Init(void)
{
memset(Head,0,sizeof(Head));
TOT=1;
}
void add(int x,int y,int z)
{
ver[++tot]=y,edge[tot]=z;
nt[tot]=head[x],head[x]=tot;
}
void Add(int x,int y,int z)
{
Ver[++TOT]=y,Edge[TOT]=z;
Nt[TOT]=Head[x],Head[x]=TOT;
}
void get_pre(void)
{
memset(tail,0,sizeof(tail));
for(int x=1;x<=nown;x++)
{
for(int i=Head[x];i;i=Nt[i])
{
pre[i]=tail[x];
tail[x]=i;
}
}
}
void del(int x,int i)
{
if(Head[x]==i) Head[x]=Nt[i];
else Nt[pre[i]]=Nt[i];
if(tail[x]==i) tail[x]=pre[i];
else pre[Nt[i]]=pre[i];
}
void build(int x,int fa)
{
int now=0;
for(int i=head[x];i;i=nt[i])
{
int y=ver[i],z=edge[i];
if(y==fa) continue;
if(!now)
{
Add(x,y,z),Add(y,x,z);
now=x;
}
else
{
ha[++nown]=false;
Add(nown,now,0),Add(now,nown,0);
Add(y,nown,z),Add(nown,y,z);
now=nown;
}
build(y,x);
}
}
void rebuild(void)
{
Init();
nown=n;
for(int i=1;i<=nown;i++) ha[i]=1;
build(1,0);
get_pre();
init();
}
struct point
{
int y;
int dis;
point(){}
point(int a,int b)
{
y=a,dis=b;
}
friend bool operator <(const point &a,const point &b)
{
return a.dis<b.dis;
}
};
struct node
{
int root,midlen,ans;
int lson,rson;
priority_queue<point>q;
}t[maxn<<1];
void _init(void)
{
for(int i=1;i<maxn<<2;i++)
{
while(t[i].q.size())
t[i].q.pop();
t[i].lson=t[i].rson=0;
}
cnt=1;
}
void dfs_size(int x,int fa,int dis)
{
add(x,root,dis);
if(ha[x]) t[root].q.push(point(x,dis));
d[x]=1;
for(int i=Head[x];i;i=Nt[i])
{
int y=Ver[i],z=Edge[i];
if(y==fa) continue;
dfs_size(y,x,dis+z);
d[x]+=d[y];
}
}
void dfs_midedge(int x,int nowi)
{
if(max(d[x],d[t[root].root]-d[x])<maxx)
{
maxx=max(d[x],d[t[root].root]-d[x]);
midedge=nowi;
}
for(int i=Head[x];i;i=Nt[i])
{
int y=Ver[i];
if(i!=(nowi^1)) dfs_midedge(y,i);
}
}
void pushup(int id)
{
t[id].ans=-1;
while(t[id].q.size()&&ha[t[id].q.top().y]==0) t[id].q.pop();
int lson=t[id].lson,rson=t[id].rson;
if(lson==0&&rson==0)
{
if(ha[t[id].root]) t[id].ans=0;
}
else
{
if(t[lson].ans>t[id].ans) t[id].ans=t[lson].ans;
if(t[rson].ans>t[id].ans) t[id].ans=t[rson].ans;
if(t[lson].q.size()&&t[rson].q.size())
t[id].ans=max(t[id].ans,t[lson].q.top().dis+t[rson].q.top().dis+t[id].midlen);
}
}
void dfs(int id,int x)
{
root=id,maxx=nown,midedge=0;
t[id].root=x;
dfs_size(x,0,0);
dfs_midedge(x,0);
if(midedge)
{
int p1=Ver[midedge];
int p2=Ver[midedge^1];
t[id].midlen=Edge[midedge];
t[id].lson=++cnt;
t[id].rson=++cnt;
del(p1,midedge^1);
del(p2,midedge);
dfs(t[id].lson,p1);
dfs(t[id].rson,p2);
}
pushup(id);
}
void update(int x)
{
ha[x]^=1;
for(int i=head[x];i;i=nt[i])
{
int y=ver[i],z=edge[i];
if(ha[x]==1) t[y].q.push(point(x,z));
pushup(y);
}
}
int main(void)
{
n=read();
init();
cnt=1;
int x,y;
for(int i=1;i<n;i++)
{
x=read(),y=read();
add(x,y,1);
add(y,x,1);
}
rebuild();
dfs(1,1);
int m,pos;
char str;
m=read();
for(int i=1;i<=m;i++)
{
str=read_charA();
if(str=='G')
{
if(t[1].ans==-1) printf("They have disappeared.\n");
else printf("%d\n",t[1].ans);
}
else
{
pos=read();
update(pos);
}
}
return 0;
}
2020/9/24更新:
考虑本题的点分治做法。
对于点分树上的每个以 x x x 为根的子树 ,我们记录 m a x ( x ) max(x) max(x) 为点分树上以 x x x 为根的子树中的节点,到点分树上 x x x 的父亲 f a ( x ) fa(x) fa(x) 在原树上的最大距离。
对于点分树上的每一点 x x x,我们记录其 m a x ( s o n ( x ) ) max(son(x)) max(son(x)) 的最大值和次大值。此时全局最大的每个点的 m a x ( s o n ( x ) ) max(son(x)) max(son(x)) 的最大值加次大值即为答案。注意:若当前点 x x x 为黑点,那么我们需要再记录一个 0 0 0 ,表示到当前点也可以。
考虑修改,我们可以每个节点开两个大顶堆维护,以当前节点为根的子树中的节点到父亲节点的最大值,儿子节点的 m a x max max。删除的时候利用懒惰删除大法,只标记不删除。
然后开一个全局的大顶堆维护答案即可。
时间复杂度: O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<unordered_map>
#include<set>
namespace onlyzhao
{
#define ui unsigned int
#define ll long long
#define llu unsigned ll
#define ld long double
#define pr make_pair
#define pb push_back
#define lc (cnt<<1)
#define rc (cnt<<1|1)
#define len(x) (t[(x)].r-t[(x)].l+1)
#define tmid ((l+r)>>1)
#define fhead(x) for(int i=head[(x)];i;i=nt[i])
//#define max(x,y) ((x)>(y)?(x):(y))
//#define min(x,y) ((x)>(y)?(y):(x))
#define one(n) for(int i=1;i<=(n);i++)
#define rone(n) for(int i=(n);i>=1;i--)
#define fone(i,x,n) for(int i=(x);i<=(n);i++)
#define frone(i,n,x) for(int i=(n);i>=(x);i--)
#define fonk(i,x,n,k) for(int i=(x);i<=(n);i+=(k))
#define fronk(i,n,x,k) for(int i=(n);i>=(x);i-=(k))
#define two(n,m) for(int i=1;i<=(n);i++) for(int j=1;j<=(m);j++)
#define ftwo(i,n,j,m) for(int i=1;i<=(n);i++) for(int j=1;j<=(m);j++)
#define fvc(vc) for(int i=0;i<vc.size();i++)
#define frvc(vc) for(int i=vc.size()-1;i>=0;i--)
#define forvc(i,vc) for(int i=0;i<vc.size();i++)
#define forrvc(i,vc) for(int i=vc.size()-1;i>=0;i--)
#define cls(a) memset(a,0,sizeof(a))
#define cls1(a) memset(a,-1,sizeof(a))
#define clsmax(a) memset(a,0x3f,sizeof(a))
#define clsmin(a) memset(a,0x80,sizeof(a))
#define cln(a,num) memset(a,0,sizeof(a[0])*num)
#define cln1(a,num) memset(a,-1,sizeof(a[0])*num)
#define clnmax(a,num) memset(a,0x3f,sizeof(a[0])*num)
#define clnmin(a,num) memset(a,0x80,sizeof(a[0])*num)
#define sc(x) scanf("%d",&x)
#define sc2(x,y) scanf("%d%d",&x,&y)
#define sc3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define scl(x) scanf("%lld",&x)
#define scl2(x,y) scanf("%lld%lld",&x,&y)
#define scl3(x,y,z) scanf("%lld%lld%lld",&x,&y,&z)
#define scf(x) scanf("%lf",&x)
#define scf2(x,y) scanf("%lf%lf",&x,&y)
#define scf3(x,y,z) scanf("%lf%lf%lf",&x,&y,&z)
#define scs(x) scanf("%s",x+1)
#define scs0(x) scanf("%s",x)
#define scline(x) scanf("%[^\n]%*c",x+1)
#define scline0(x) scanf("%[^\n]%*c",x)
#define pcc(x) putchar(x)
#define pc(x) printf("%d\n",x)
#define pc2(x,y) printf("%d %d\n",x,y)
#define pc3(x,y,z) printf("%d %d %d\n",x,y,z)
#define pck(x) printf("%d ",x)
#define pcl(x) printf("%lld\n",x)
#define pcl2(x,y) printf("%lld %lld\n",x,y)
#define pcl3(x,y,z) printf("%lld %lld %d\n",x,y,z)
#define pclk(x) printf("%lld ",x)
#define pcf2(x) printf("%.2f\n",x)
#define pcf6(x) printf("%.6f\n",x)
#define pcf8(x) printf("%.8f\n",x)
#define pcs(x) printf("%s\n",x+1)
#define pcs0(x) printf("%s\n",x)
#define pcline(x) printf("%d**********\n",x)
#define casett int tt;sc(tt);int pp=0;while(tt--)
char buffer[100001],*S,*T;
inline char Get_Char()
{
if (S==T)
{
T=(S=buffer)+fread(buffer,1,100001,stdin);
if (S==T) return EOF;
}
return *S++;
}
inline int read()
{
char c;int re=0;
for(c=Get_Char();c<'0'||c>'9';c=Get_Char());
while(c>='0'&&c<='9') re=re*10+(c-'0'),c=Get_Char();
return re;
}
};
using namespace onlyzhao;
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e18;
const int mod=998244353;
const int p=mod;
const double eps=1e-8;
const double pi=acos(-1.0);
const int hp=13331;
const int maxn=100100;
const int maxm=1000100;
const int maxp=100100;
const int up=100100;
const int g=3;
int head[maxn],ver[maxn<<1],nt[maxn<<1],tot=1;
void add(int x,int y)
{
ver[++tot]=y,nt[tot]=head[x],head[x]=tot;
}
int d[maxn],id[maxn],rk[maxn<<1],dd[maxn<<1];
int f[maxn<<1][20],_log[maxn<<1];
int tcnt=0,n;
void dfs(int x,int fa)
{
id[x]=++tcnt;rk[tcnt]=x;dd[tcnt]=d[x];
for(int i=head[x];i;i=nt[i])
{
int y=ver[i];
if(y==fa) continue;
d[y]=d[x]+1;
dfs(y,x);
rk[++tcnt]=x,dd[tcnt]=d[x];
}
}
void ST(void)
{
_log[0]=-1;
for(int i=1;i<=tcnt;i++)
{
f[i][0]=i;
_log[i]=(i&(i-1))==0?_log[i-1]+1:_log[i-1];
}
int t=_log[tcnt]+1;
for(int j=1;j<=t;j++)
{
for(int i=1;i<=tcnt-(1<<j)+1;i++)
f[i][j]=dd[f[i][j-1]]<dd[f[i+(1<<(j-1))][j-1]]?f[i][j-1]:f[i+(1<<(j-1))][j-1];
}
}
int lca(int x,int y)
{
if(id[x]>id[y]) swap(x,y);
x=id[x],y=id[y];
int k=_log[y-x+1];
return dd[f[x][k]]<dd[f[y-(1<<k)+1][k]]?rk[f[x][k]]:rk[f[y-(1<<k)+1][k]];
}
int dis(int x,int y)
{
return d[x]+d[y]-2*d[lca(x,y)];
}
struct node
{
priority_queue<int>q1,q2;
node(){}
void clear()
{
while(q1.size()) q1.pop();
while(q2.size()) q2.pop();
}
void push(int x)
{
q1.push(x);
}
void erase(int x)
{
q2.push(x);
}
int max(void)
{
while(q1.size()&&q2.size()&&q1.top()==q2.top()) q1.pop(),q2.pop();
if(q1.size()) return q1.top();
else return -inf;
}
int smax(void)
{
int now=max();
if(now==-inf) return now;
q1.pop();
int nown=max();
q1.push(now);
return nown;
}
}q1[maxn],q2[maxn],ans;
int maxpart[maxn],si[maxn],fa[maxn],last[maxn],lastq1[maxn];
bool ha[maxn];
int root,maxsi;
void dfs_size(int x,int fa)
{
si[x]=1,maxpart[x]=0;
for(int i=head[x];i;i=nt[i])
{
int y=ver[i];
if(y==fa||ha[y]) continue;
dfs_size(y,x);
si[x]+=si[y];
maxpart[x]=max(maxpart[x],si[y]);
}
}
void dfs_root(int nowroot,int x,int fa)
{
maxpart[x]=max(maxpart[x],si[nowroot]-si[x]);
if(maxsi>maxpart[x])
{
maxsi=maxpart[x];
root=x;
}
for(int i=head[x];i;i=nt[i])
{
int y=ver[i];
if(y==fa||ha[y]) continue;
dfs_root(nowroot,y,x);
}
}
void dfs_dis(int rt,int x,int ffa)
{
q1[rt].push(dis(x,fa[rt]));
for(int i=head[x];i;i=nt[i])
{
int y=ver[i];
if(y==ffa||ha[y]) continue;
dfs_dis(rt,y,x);
}
}
void dfs_for_tree(int x,int f)
{
maxsi=inf;
dfs_size(x,0);
dfs_root(x,x,0);
int rt=root;
ha[rt]=true;
fa[rt]=f;
dfs_dis(rt,rt,0);
lastq1[rt]=q1[rt].max();
q2[f].push(q1[rt].max());
q2[rt].push(0);
for(int i=head[rt];i;i=nt[i])
{
int y=ver[i];
if(ha[y]) continue;
dfs_for_tree(y,rt);
}
ans.push(last[rt]=q2[rt].max()+q2[rt].smax());
}
void init(void)
{
d[0]=-1;
dfs(1,0);
ST();
dfs_for_tree(1,0);
}
bool isopen[maxn];
int close=0;
void get1(void)
{
if(close==1) printf("0\n");
else if(close==0) printf("-1\n");
else printf("%d\n",ans.max());
}
void get2(int x)
{
if(isopen[x]==false) q2[x].erase(0),close--;
else q2[x].push(0),close++;
int now,nowx=x;
for(;x;x=fa[x])
{
ans.erase(last[x]);
ans.push(last[x]=q2[x].max()+q2[x].smax());
if(isopen[nowx]==false) q1[x].erase(dis(nowx,fa[x]));
else q1[x].push(dis(nowx,fa[x]));
q2[fa[x]].erase(lastq1[x]);
q2[fa[x]].push(lastq1[x]=q1[x].max());
}
isopen[nowx]^=1;
}
int main(void)
{
scanf("%d",&n);
close=n;
int x,y;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
init();
char str[10];
int q;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
scanf("%s",str);
if(str[0]=='G') get1();
else
{
scanf("%d",&x);
get2(x);
}
}
return 0;
}