题目传送门:
BZOJ1095:http://www.lydsy.com/JudgeOnline/problem.php?id=1095
SPOJ Query on a tree IV vjudge题面:https://cn.vjudge.net/problem/SPOJ-QTREE4#
题目分析:看完题就会发现后面那题是前面那题的加强版。
这两题都可以用链剖,边分和点分实现。前两种解法可以见09年QZC的国集论文,点分的做法可以见PoPoQQQ大爷的blog。
前一题因为边权固定为1,还有一种用线段树维护括号序列的做法,见某dalao的blog。线段树维护的东西比较烦,我就没写。
以前在学链剖的时候曾经想过会不会有用这种算法动态维护DP值的题目,今天终于见到了,果然是一道很神的题。至于括号序列之类的,它的性质我很早前就忘了QAQ。
我把点分和链剖的code都写了一遍,写链剖的原因是BZOJ上我动态点分治的AC代码到SPOJ上就TLE了可能是因为我点分写得丑。链剖的常数明显要比动态点分治小很多,据论文里面说“这是因为链的长度和链的个数相互制约”。
两种方法都码了大概1.5h左右,不过链剖好写一些。另外如果不用STL的priority_queue的话,代码长度真的会死人的……
(回去多复习点分治和括号序列)
CODE(动态点分治):
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn=100100;
const int maxl=22;
const int oo=1e9;
struct edge
{
int obj;
edge *Next;
} e[maxn<<1];
edge *head[maxn];
int cur=-1;
int Mid[maxn][maxl]; //每个点每次被覆盖时的分治中心
int Fa[maxn][maxl]; //分治时对应的子树的根,自身为分治中心则为0
int Dep[maxn][maxl]; //分治时离分治中心的距离
int num[maxn]; //统计次数
int Size[maxn];
int max_Size[maxn];
int tree[maxn];
int cnt;
struct Heap
{
priority_queue <int> ins,del;
} ;
Heap dis[maxn][maxl]; //每个点作为分治中心的直接儿子时,存储的所有黑点深度
Heap max_dis[maxn]; //每个点作为分治中心时,每个子树加它自身的最大深度
Heap ans; //答案
vector <int> Son[maxn]; //每个点作为分治中心时的直接儿子
bool vis[maxn];
int col[maxn];
int n,m;
void Add(int x,int y)
{
cur++;
e[cur].obj=y;
e[cur].Next=head[x];
head[x]=e+cur;
}
void Dfs(int node,int fa)
{
tree[++cnt]=node;
Size[node]=1;
max_Size[node]=0;
for (edge *p=head[node]; p; p=p->Next)
{
int son=p->obj;
if ( son==fa || vis[son] ) continue;
Dfs(son,node);
Size[node]+=Size[son];
max_Size[node]=max(max_Size[node],Size[son]);
}
}
void Work(int node,int fa,int dep,int id,int root)
{
++num[node];
Mid[node][ num[node] ]=root;
Fa[node][ num[node] ]=id;
Dep[node][ num[node] ]=dep;
dis[id][ num[id] ].ins.push(dep);
for (edge *p=head[node]; p; p=p->Next)
{
int son=p->obj;
if ( son==fa || vis[son] ) continue;
Work(son,node,dep+1,id,root);
}
}
int Max(Heap &s)
{
while ( !s.del.empty() && s.ins.top()==s.del.top() )
s.ins.pop(),s.del.pop();
if (s.ins.empty()) return -oo;
return s.ins.top();
}
int Max2(Heap &s)
{
int val=Max(s);
if (val==-oo) return -oo;
s.ins.pop();
while ( !s.del.empty() && s.ins.top()==s.del.top() )
s.ins.pop(),s.del.pop();
int temp;
if (s.ins.empty()) temp=-oo;
else temp=s.ins.top();
s.ins.push(val);
return temp;
}
void Solve(int node)
{
cnt=0;
Dfs(node,node);
if (cnt==-1) return;
int root=tree[1];
for (int i=1; i<=cnt; i++)
{
int x=tree[i];
max_Size[x]=max(max_Size[x],Size[node]-Size[x]);
if (max_Size[x]<max_Size[root]) root=x;
}
for (edge *p=head[root]; p; p=p->Next)
{
int son=p->obj;
if (vis[son]) continue;
Son[root].push_back(son);
Work(son,root,1,son,root);
max_dis[root].ins.push( Max(dis[son][ num[son] ]) );
}
++num[root];
Mid[root][ num[root] ]=root;
max_dis[root].ins.push(0);
ans.ins.push( Max(max_dis[root])+Max2(max_dis[root]) );
vis[root]=true;
for (int i=0; i<Son[root].size(); i++) Solve(Son[root][i]);
}
void Insert(int node)
{
for (int i=num[node]; i>=1; i--)
{
int root=Mid[node][i];
if (root==node)
{
ans.del.push( Max(max_dis[root])+Max2(max_dis[root]) );
max_dis[root].ins.push(0);
ans.ins.push( Max(max_dis[root])+Max2(max_dis[root]) );
}
else
{
int id=Fa[node][i];
ans.del.push( Max(max_dis[root])+Max2(max_dis[root]) );
max_dis[root].del.push( Max(dis[id][i]) );
dis[id][i].ins.push(Dep[node][i]);
max_dis[root].ins.push( Max(dis[id][i]) );
ans.ins.push( Max(max_dis[root])+Max2(max_dis[root]) );
}
}
}
void Delete(int node)
{
for (int i=num[node]; i>=1; i--)
{
int root=Mid[node][i];
if (root==node)
{
ans.del.push( Max(max_dis[root])+Max2(max_dis[root]) );
max_dis[root].del.push(0);
ans.ins.push( Max(max_dis[root])+Max2(max_dis[root]) );
}
else
{
int id=Fa[node][i];
ans.del.push( Max(max_dis[root])+Max2(max_dis[root]) );
max_dis[root].del.push( Max(dis[id][i]) );
dis[id][i].del.push(Dep[node][i]);
max_dis[root].ins.push( Max(dis[id][i]) );
ans.ins.push( Max(max_dis[root])+Max2(max_dis[root]) );
}
}
}
int main()
{
freopen("1095.in","r",stdin);
freopen("1095.out","w",stdout);
scanf("%d",&n);
for (int i=1; i<=n; i++) head[i]=NULL;
for (int i=1; i<n; i++)
{
int x,y;
scanf("%d%d",&x,&y);
Add(x,y);
Add(y,x);
}
for (int i=1; i<=n; i++) col[i]=1;
int val=n;
Solve(1);
scanf("%d",&m);
for (int i=1; i<=m; i++)
{
char c=getchar();
while ( c!='G' && c!='C' ) c=getchar();
if (c=='G')
{
if (!val) printf("-1\n");
if (val==1) printf("0\n");
if (val>1) printf("%d\n", Max(ans) );
}
else
{
int x;
scanf("%d",&x);
if (!col[x]) Insert(x),val++;
else Delete(x),val--;
col[x]^=1;
}
}
return 0;
}
CODE(树链剖分):
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=100100;
const int oo=1050000000;
struct edge
{
int obj,len;
edge *Next;
} e[maxn<<1];
edge *head[maxn];
int cur=-1;
int fa[maxn];
int dep[maxn];
int Size[maxn];
int Son[maxn];
int Top[maxn];
int max_dep[maxn];
int Len[maxn];
int dfn[maxn];
int dfsx[maxn];
int Time=0;
struct Heap
{
priority_queue <int> ins,del;
} Light[maxn];
Heap ans;
struct Seg
{
int Lmax,Rmax,opt,sum;
Seg *Lson,*Rson;
} tree[maxn<<2];
Seg *Root[maxn];
int cnt=-1;
int col[maxn];
int n,m;
void Add(int x,int y,int z)
{
cur++;
e[cur].obj=y;
e[cur].len=z;
e[cur].Next=head[x];
head[x]=e+cur;
}
void Dfs1(int node)
{
Size[node]=1;
for (edge *p=head[node]; p; p=p->Next)
{
int son=p->obj;
if (son==fa[node]) continue;
fa[son]=node;
dep[son]=dep[node]+1;
Dfs1(son);
Size[node]+=Size[son];
if (Size[son]>Size[ Son[node] ]) Son[node]=son;
}
}
void Dfs2(int node)
{
dfsx[++Time]=node;
dfn[node]=Time;
max_dep[ Top[node] ]=max(max_dep[ Top[node] ],dep[node]);
int t=Time;
if (Son[node]) Top[ Son[node] ]=Top[node],Dfs2(Son[node]);
for (edge *p=head[node]; p; p=p->Next)
{
int son=p->obj;
if (son==Son[node]) Len[t]=p->len;
if ( son==fa[node] || son==Son[node] ) continue;
Len[Time]=p->len;
Top[son]=son;
Dfs2(son);
}
}
Seg *New_seg()
{
cur++;
return tree+cur;
}
int Max(Heap &s)
{
while ( !s.del.empty() && s.ins.top()==s.del.top() ) s.ins.pop(),s.del.pop();
if (s.ins.empty()) return -oo;
return s.ins.top();
}
int Max2(Heap &s)
{
int val=Max(s);
if (val==-oo) return val;
s.del.push(val);
int temp=Max(s);
s.ins.push(val);
return temp;
}
void Up(Seg *root,int x)
{
root->Lmax=max(root->Lson->sum+x+root->Rson->Lmax,root->Lson->Lmax);
root->Rmax=max(root->Rson->sum+x+root->Lson->Rmax,root->Rson->Rmax);
root->opt=max(root->Lson->opt,root->Rson->opt);
root->opt=max(root->opt,root->Lson->Rmax+x+root->Rson->Lmax);
}
void Build(Seg *root,int L,int R)
{
if (L==R)
{
int node=dfsx[L];
root->Lmax=root->Rmax=Max(Light[node]);
root->opt=root->Lmax+Max2(Light[node]);
root->sum=0;
return;
}
int mid=(L+R)>>1;
root->Lson=New_seg();
Build(root->Lson,L,mid);
root->Rson=New_seg();
Build(root->Rson,mid+1,R);
Up(root,Len[mid]);
root->sum=root->Lson->sum+root->Rson->sum+Len[mid];
}
void DP(int node)
{
Light[node].ins.push(0);
for (edge *p=head[node]; p; p=p->Next)
{
int son=p->obj;
if (son==fa[node]) continue;
DP(son);
if (son!=Son[node]) Light[node].ins.push(Root[son]->Lmax+p->len);
}
if (node==Top[node])
{
Root[node]=New_seg();
Build(Root[node],dfn[node],dfn[node]-dep[node]+max_dep[node]);
ans.ins.push(Root[node]->opt);
}
}
void Update(Seg *root,int L,int R,int x)
{
if (L==R)
{
int node=dfsx[L];
root->Lmax=root->Rmax=Max(Light[node]);
root->opt=root->Lmax+Max2(Light[node]);
return;
}
int mid=(L+R)>>1;
if (x<=mid) Update(root->Lson,L,mid,x);
else Update(root->Rson,mid+1,R,x);
Up(root,Len[mid]);
}
void Work(int node,int id)
{
if (id) Light[node].ins.push(0);
else Light[node].del.push(0);
while (node)
{
int up=Top[node];
ans.del.push(Root[up]->opt);
if (fa[up]) Light[ fa[up] ].del.push( Root[up]->Lmax+Len[ dfn[up]-1 ] );
Update(Root[up],dfn[up],dfn[up]-dep[up]+max_dep[up],dfn[node]);
if (fa[up]) Light[ fa[up] ].ins.push( Root[up]->Lmax+Len[ dfn[up]-1 ] );
ans.ins.push(Root[up]->opt);
node=fa[up];
}
}
int main()
{
freopen("1095.in","r",stdin);
freopen("1095.out","w",stdout);
scanf("%d",&n);
for (int i=1; i<=n; i++) head[i]=NULL;
for (int i=1; i<n; i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
Add(x,y,z);
Add(y,x,z);
}
dep[1]=1;
Dfs1(1);
Top[1]=1;
Dfs2(1);
DP(1);
int val=n;
for (int i=1; i<=n; i++) col[i]=1;
scanf("%d",&m);
for (int i=1; i<=m; i++)
{
char c=getchar();
while ( c!='A' && c!='C' ) c=getchar();
if (c=='A')
if (!val) printf("They have disappeared.\n");
else if (val==1) printf("0\n");
else printf("%d\n", max(0, Max(ans)) ); //!!!
else
{
int x;
scanf("%d",&x);
if (col[x]) Work(x,0),val--;
else Work(x,1),val++;
col[x]^=1;
}
}
return 0;
}