BZOJ 3083 遥远的国度
这题的与 HAOI 2015T2 的不同点在于其有换根操作,但按照普通的思路我们可以发现,换根之后树的形态会有改变,每个节点的子树会发生改变,所以我们来分类讨论。
修改链的操作不会发生改变,现在只考虑子树minn。为了方便,我们定义现在的换的“根节点”为root(但实际上树的根节点为1),子树根为x,黑圈标明查询范围;
情况一 x=root,很显然此时应当查询整棵树。
情况二 lca(root,x)!=x ,此时直接查询x的子树即可,与换根无关。
情况三,lca(root,x)=x,此时我们应当查询与x相邻的节点中与root最近的点v在整棵树中的补集
可以发现v一定在root到x的链上,且一定是x在这条链上的儿子,倍增法可以求得v
code:
#include
#include
#include
#define mid (l+r)/2
#define lch i<<1,l,mid
#define rch i<<1|1,mid+1,r
#define inf 2147483647
using namespace std;
struct hp{
int fat,dep,size,wson,top,ls,rs;
int lca[18];
}tree[100001];
struct hq{
int u,v;
}a[200001];
struct hr{
int minn,delta;
}seg[400001];
int point[100001],next[100001];
int val[400001],plc[100001];
int n,m,ans,e=1,totw=0,root;
void add(int x,int y)
{
e++; a[e].u=x; a[e].v=y; next[e]=point[x]; point[x]=e;
e++; a[e].u=y; a[e].v=x; next[e]=point[y]; point[y]=e;
}
void build_tree(int last,int x,int depth)
{
int i;
tree[x].lca[0]=tree[x].fat=last;
tree[x].size=1;
tree[x].wson=0;
tree[x].dep=depth;
for (i=1;i<=17;++i)
{
if (tree[x].dep >= 1<=r)
{
paint(i,a);
return;
}
if (seg[i].delta!=0)
pushdown(i);
if (x<=mid) insert_seg(lch,x,y,a);
if (y>mid) insert_seg(rch,x,y,a);
updata(i);
}
void insert(int x,int y,int a)
{
int f1=tree[x].top,f2=tree[y].top;
while (f1!=f2)
{
if (tree[f1].deptree[y].dep) swap(x,y);
insert_seg(1,1,n,plc[x],plc[y],a);
}
int bz(int x,int depth)
{
int i,v=x;
for (i=0;i<=17;++i)
{
if (depth&(1<=r)
{
ans=min(ans,seg[i].minn);
return;
}
if (seg[i].delta!=0)
pushdown(i);
if (x<=mid) query_seg(lch,x,y);
if (y>mid) query_seg(rch,x,y);
}
int LCA(int x,int y)
{
int i,t;
if (tree[x].dep=0;--i)
if (tree[x].lca[i]!=tree[y].lca[i])
{x=tree[x].lca[i]; y=tree[y].lca[i];}
if (x==y) return x;
else return tree[x].fat;
}
void work(int x)
{
int lca,v,rootx=root,xx=x;
lca=LCA(root,x);
if (rootx==xx)//情况1
printf("%d\n",seg[1].minn);
else
{
if (lca!=xx)//情况2
query_seg(1,1,n,tree[xx].ls,tree[xx].rs);
else//情况三
{
v=bz(rootx,tree[rootx].dep-tree[xx].dep-1);
if (tree[v].ls>1)
query_seg(1,1,n,1,tree[v].ls-1);
if (tree[v].rs