bzoj3083: 遥远的国度

题意:有棵树,每个点有权值,三种操作,1,修改根,2.把a到b的路径上的点权值修改为c,3,查询以a为子树的最小权值
题解:毒瘤树链剖分,树链剖分是能处理链和子树的修改查询的,因为树链剖分本质还是dfs序线段树,然后现在问题就变成了换根,假设根为root
1.root为a,直接查询整棵树,2.lca(root,a)!=a,直接查询a子树,3.lca(root,a)==a,这时a是root的祖先,需要查询的子树是除了a到root路径上的直接儿子的子树的整棵树,分成两段即可,假设直接儿子是x,那么就是(1,l[x]-1),(r[x]+1,n);

/**************************************************************
    Problem: 3083
    User: walfy
    Language: C++
    Result: Accepted
    Time:6272 ms
    Memory:26228 kb
****************************************************************/
 
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
//#pragma GCC optimize(4)
//#pragma GCC optimize("unroll-loops")
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include<bits/stdc++.h>
#define fi first
#define se second
#define db double
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000009
#define ld long double
//#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define ull unsigned long long
//#define base 1000000000000000000
#define fin freopen("a.txt","r",stdin)
#define fout freopen("a.txt","w",stdout)
#define fio ios::sync_with_stdio(false);cin.tie(0)
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline void sub(ll &a,ll b){a-=b;if(a<0)a+=mod;}
inline void add(ll &a,ll b){a+=b;if(a>=mod)a-=mod;}
template<typename T>inline T const& MAX(T const &a,T const &b){return a>b?a:b;}
template<typename T>inline T const& MIN(T const &a,T const &b){return a<b?a:b;}
inline ll qp(ll a,ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
inline ll qp(ll a,ll b,ll c){ll ans=1;while(b){if(b&1)ans=ans*a%c;a=a*a%c,b>>=1;}return ans;}
 
using namespace std;
 
const ull ba=233;
const db eps=1e-5;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int N=100000+10,maxn=1000000+10,inf=0x3f3f3f3f;
 
ll a[N],mi[N<<2],lazy[N<<2];
int son[N],dep[N],sz[N],fa[N][20],top[N],id[N],l[N],r[N];
int head[N],cnt,res;
struct edge{int to,Next;}e[N<<1];
void add(int u,int v){e[cnt].to=v,e[cnt].Next=head[u];head[u]=cnt++;}
void init(){cnt=0;memset(head,-1,sizeof head);memset(son,-1,sizeof son);}
void dfs1(int u,int f,int de)
{
    fa[u][0]=f;sz[u]=1;dep[u]=de;
    for(int i=head[u];~i;i=e[i].Next)
    {
        int x=e[i].to;
        if(x!=f)
        {
            dfs1(x,u,de+1);sz[u]+=sz[x];
            if(son[u]==-1||sz[x]>sz[son[u]])son[u]=x;
        }
    }
}
void dfs2(int u,int f,int tp)
{
    top[u]=tp;l[u]=++res;id[res]=u;
    if(son[u]!=-1)dfs2(son[u],u,tp);
    for(int i=head[u];~i;i=e[i].Next)
    {
        int x=e[i].to;
        if(x!=f&&x!=son[u])dfs2(x,u,x);
    }
    r[u]=res;
}
void pushdown(int rt)
{
    if(lazy[rt])
    {
        mi[rt<<1]=mi[rt<<1|1]=lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
        lazy[rt]=0;
    }
}
void build(int l,int r,int rt)
{
    if(l==r){mi[rt]=a[id[l]];return ;}
    int m=(l+r)>>1;
    build(ls);build(rs);
    mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
}
void update(int L,int R,ll v,int l,int r,int rt)
{
    if(L<=l&&r<=R){mi[rt]=lazy[rt]=v;return ;}
    pushdown(rt);
    int m=(l+r)>>1;
    if(L<=m)update(L,R,v,ls);
    if(m<R)update(L,R,v,rs);
    mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
}
void change(int a,int b,ll c)
{
    int f1=top[a],f2=top[b];
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])swap(f1,f2),swap(a,b);
        update(l[f1],l[a],c,1,res,1);
        a=fa[f1][0],f1=top[a];
    }
    if(dep[a]>dep[b])swap(a,b);
    update(l[a],l[b],c,1,res,1);
}
ll query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)return mi[rt];
    pushdown(rt);
    int m=(l+r)>>1;ll ans=INF;
    if(L<=m)ans=min(ans,query(L,R,ls));
    if(m<R)ans=min(ans,query(L,R,rs));
    return ans;
}
int lca(int x,int y)
{
    if(dep[x]>dep[y])swap(x,y);
    for(int i=19;i>=0;i--)if(((dep[y]-dep[x])>>i)&1)y=fa[y][i];
    if(x==y)return x;
    for(int i=19;i>=0;i--)
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
int main()
{
//    fin;
    int n,m;scanf("%d%d",&n,&m);
    init();
    for(int i=1;i<n;i++)
    {
        int a,b;scanf("%d%d",&a,&b);
        add(a,b);add(b,a);
    }
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    int root;scanf("%d",&root);
    int rr=root;
    dfs1(root,0,1);dfs2(root,0,root);
    build(1,n,1);
    for(int i=1;i<20;i++)for(int j=1;j<=n;j++)fa[j][i]=fa[fa[j][i-1]][i-1];
    while(m--)
    {
        int op,a,b;ll c;scanf("%d",&op);
        if(op==1){scanf("%d",&a),rr=a;}
        else if(op==2){scanf("%d%d%lld",&a,&b,&c);change(a,b,c);}
        else
        {
            scanf("%d",&a);
            if(a==rr)printf("%lld\n",mi[1]);
            else if(lca(rr,a)!=a)printf("%lld\n",query(l[a],r[a],1,n,1));
            else
            {
                int y=rr,x=dep[a]+1;
                for(int i=19;i>=0;i--)if(((dep[y]-x)>>i)&1)y=fa[y][i];
                ll ans=INF;
                if(l[y]>1)ans=min(ans,query(1,l[y]-1,1,n,1));
                if(r[y]<n)ans=min(ans,query(r[y]+1,n,1,n,1));
                printf("%lld\n",ans);
            }
        }
    }
    return 0;
}
/********************
5 2
4 2
2 5
5 3
3 1
490 387 927 484 130
3
1 2
3 3
********************/
posted @ 2019-03-06 14:16  walfy  阅读(232)  评论(0编辑  收藏  举报