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

来源:互联网 发布:工业组态软件 编辑:程序博客网 时间:2024/05/16 15:55

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<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>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]]<tot[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(l<r)    {        int 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]<dep[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;i<n;i++)    {        int 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]<dep[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;}
原创粉丝点击