[bzoj3083][树链剖分][lca]遥远的国度

Description

描述
zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。

问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。

Input

第1行两个整数n m,代表城市个数和操作数。 第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。
第n+1行,有n个整数,代表所有点的初始防御值。 第n+2行一个整数 id,代表初始的首都为id。
第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1
p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数
id,代表询问以城市id为根的子树中的最小防御值。

Output

对于每个opt=3的操作,输出一行代表对应子树的最小点权值。

Sample Input

3 7
1 2
1 3
1 2 3
1
3 1
2 1 1 6
3 1
2 2 2 5
3 1
2 3 3 4
3 1

Sample Output

1
2
3
4

HINT

提示

对于20%的数据,n<=1000 m<=1000。

对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。

对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。

对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。

对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。

题解

其实我一开始看到换根我想用lct的。但是好像这个操作太多了lct常数巨大直接tle
怎么办?很痛苦?来一个树剖筋骨贴
看一看换根的操作,其实换不换根的情况下,树中一个点到另一个点的路径其实是固定的。那么2操作我们可以直接修改
那换根怎么查找??反正肯定不能直接搞对不对。。
设当前询问的是now点,根为id
1、如果id是在原树中以now为根的子树的外面,那么其实是不影响的对不对
2、如果id就是now,那么询问的实质上就变成了整棵树的权
3、如果id在now的子树里面呢?那么实际上就是砍掉了id所在now的那棵子树,然后询问全树的权
拿lca判id在now的哪个部分,如果在now的树里面就倍增求出他在哪棵子树
之后慢慢查找就好了
所以说。。这样就可以水过去了???!!!!
YES!

#include
#include
#include
#include
#include
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct node
{
    int x,y,next;   
}a[411000];int len,last[411000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
int bin[25];
int fa[411000][25],tot[411000],son[411000],dep[411000];
void pre_tree_node(int x)
{
    tot[x]=1;son[x]=0;
    for(int i=1;bin[i]<=dep[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa[x][0])
        {
            fa[y][0]=x;
            dep[y]=dep[x]+1;
            pre_tree_node(y);
            if(tot[son[x]]y])son[x]=y;
            tot[x]+=tot[y];
        }
    }
}
int ys[411000],z,top[411000];
void pre_tree_edge(int x,int tp)
{
    ys[x]=++z;top[x]=tp;
    if(son[x]!=0)pre_tree_edge(son[x],tp);
    for(int k=last[x];k;k=a[k].next)
        if(a[k].y!=fa[x][0] && a[k].y!=son[x])pre_tree_edge(a[k].y,a[k].y);
}
struct trnode
{
    int lc,rc,l,r,c;
    int lazy;
}tr[411000];int trlen;
void bt(int l,int r)
{
    int now=++trlen;
    tr[now].l=l;tr[now].r=r;
    tr[now].lc=tr[now].rc=-1;tr[now].c=0;
    tr[now].lazy=-1;
    if(lint mid=(l+r)/2;
        tr[now].lc=trlen+1;bt(l,mid);
        tr[now].rc=trlen+1;bt(mid+1,r);
    }
}
void upd(int x)
{
    int lc=tr[x].lc,rc=tr[x].rc;
    tr[lc].c=tr[x].lazy;tr[rc].c=tr[x].lazy;
    tr[lc].lazy=tr[rc].lazy=tr[x].lazy;
    tr[x].lazy=-1;
}
void change(int now,int l,int r,int c)
{
    if(tr[now].l==l && tr[now].r==r)
    {
        tr[now].c=tr[now].lazy=c;
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(tr[now].l+tr[now].r)/2;
    if(tr[now].lazy!=-1)upd(now);
    if(r<=mid)change(lc,l,r,c);
    else if(mid+1<=l)change(rc,l,r,c);
    else
    {
        change(lc,l,mid,c);
        change(rc,mid+1,r,c);
    }
    tr[now].c=min(tr[lc].c,tr[rc].c);
}
int solmin(int now,int l,int r)
{
    if(tr[now].l==l && tr[now].r==r){return tr[now].c;}
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(tr[now].l+tr[now].r)/2;
    if(tr[now].lazy!=-1)upd(now);
    if(r<=mid)return solmin(lc,l,r);
    else if(mid+1<=l)return solmin(rc,l,r);
    else return min(solmin(lc,l,mid),solmin(rc,mid+1,r));
}
int lca(int x,int y,int op)
{
    if(dep[x]y])swap(x,y);
    int tmp=x;
    for(int i=20;i>=0;i--)if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
    if(x==y)
    {
        if(op==0)return x;
        for(int i=20;i>=0;i--)if(dep[fa[tmp][i]]>=dep[son[y]])tmp=fa[tmp][i];
        return tmp;
    }
    for(int i=20;i>=0;i--)if(dep[x]>=bin[i] && fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
    if(op==0)return fa[x][0];
    return x;
}
void chmul(int x,int y,int c)
{
    int tx=top[x],ty=top[y];
    while(tx!=ty)
    {
        if(dep[tx]>dep[ty])swap(x,y),swap(tx,ty);
        change(1,ys[ty],ys[y],c);
        y=fa[ty][0];ty=top[y];
    }
    if(x==y){change(1,ys[x],ys[x],c);return ;}
    else
    {
        if(dep[x]>dep[y])swap(x,y);
        change(1,ys[x],ys[y],c);
    }
}
int id;
int main()
{
    int n,m;
    bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]*2;
    n=read();m=read();
    len=0;memset(last,0,sizeof(last));
    for(int i=1;iint x=read(),y=read();
        ins(x,y);ins(y,x);
    }
    fa[1][0]=0;dep[1]=1;pre_tree_node(1);
    z=0;pre_tree_edge(1,1);
    trlen=0;bt(1,z);
    for(int i=1;i<=n;i++)
    {
        int x=read();
        change(1,ys[i],ys[i],x);
    }
    id=read();
    while(m--)
    {
        int op,x,y,c;
        op=read();x=read();
        if(op==1)id=x;
        else if(op==2)
        {
            y=read();c=read();
            chmul(x,y,c);
        }
        else
        {
            int cnt=lca(x,id,0);
            if(dep[cnt]x])printf("%d\n",solmin(1,ys[x],ys[x]+tot[x]-1));
            else if(x==id)printf("%d\n",solmin(1,1,z));
            else
            {
                int num=lca(x,id,1);
                if(ys[num]+tot[num]<=z)printf("%d\n",min(solmin(1,1,ys[num]-1),solmin(1,ys[num]+tot[num],z)));
                else printf("%d\n",solmin(1,1,ys[num]-1));
            }
        }
    }
    return 0;
}

你可能感兴趣的:(bzoj,树链剖分,树上倍增,OI路漫漫)