zoukankan      html  css  js  c++  java
  • bzoj3083: 遥远的国度

    树链剖分。

    除去换根的俩个操作,在树链剖分后很容易实现。

    换根以后只需操作的时候进行分类讨论即可。

    操作2不会受到换根的影响。

    操作3:如果询问点就是根,输出整个线段树最小值。

              如果询问点在根到1的路径上,查询(1,st[p])和(ed[p]+1,n)的最小值,st和ed分别为出入栈的编号,p为路径上最靠近询问点的点。

             其他情况下,输出范围(st[u],ed[u])的最小值,u为询问点。

    细节方面要注意的是,一定要求p,因为ed[p+1]不一定等于ed[u],u为询问点。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn = 200000 + 10;
    const int maxm= 1600000 + 10;
    const int inf = 0x7fffffff;
    const int maxh = 25;
    
    int g[maxn],v[maxm],next[maxm],eid;
    int root[maxm],st[maxm],ed[maxm];
    int dep[maxn],anc[maxn][maxh],size[maxn],son[maxn];
    int n,m,vid,cap,op,x,y,val;
    
    void addedge(int a,int b) {
        v[eid]=b; next[eid]=g[a]; g[a]=eid++;
        v[eid]=a; next[eid]=g[b]; g[b]=eid++;
    }
    
    struct Segtree {
        #define lc(x) ((x)<<1)
        #define rc(x) (((x)<<1)|1)
        
        int l[maxm],r[maxm];
        int minv[maxm],sam[maxm];
        
        inline void update(int x) {
            minv[x]=min(minv[lc(x)],minv[rc(x)]);
        }
        
        void push(int x) {
            if(!sam[x]) return;
            minv[lc(x)]=sam[lc(x)]=sam[x];
            minv[rc(x)]=sam[rc(x)]=sam[x];
            sam[x]=0;
        }
        
        void change(int x,int L,int R,int val) {
            if(L>r[x] || R<l[x]) return;
            if(L<=l[x] && r[x]<=R) {
                minv[x]=sam[x]=val;
                return;
            }
            push(x);
            change(lc(x),L,R,val);
            change(rc(x),L,R,val);
            update(x);
        }
        
        int query(int x,int L,int R) {
            if(L>r[x] || R<l[x]) return inf;
            if(L<=l[x] && r[x]<=R) return minv[x];
            push(x);
            return min(query(lc(x),L,R),query(rc(x),L,R));
        }
        
        void build(int x,int L,int R) {
            l[x]=L; r[x]=R;
            if(L==R) {
                minv[x]=sam[x]=0;
                return;
            }
            int mid=(L+R)>>1;
            build(lc(x),L,mid);
            build(rc(x),mid+1,R);
        }
    }seg;
    
    void dfs1(int u) {
        dep[u]=dep[anc[u][0]]+1;
        size[u]=1;
        for(int h=1;h<maxh;h++) anc[u][h]=anc[anc[u][h-1]][h-1];
        
        for(int i=g[u];~i;i=next[i]) if(v[i]!=anc[u][0]) {
            anc[v[i]][0]=u;
            dfs1(v[i]);
            size[u]+=size[v[i]];
            if(size[v[i]]>size[son[u]]) son[u]=v[i];    
        }
    }
    
    void dfs2(int u,int r) {
        root[u]=r; st[u]=++vid; //ID[vid]=u;
        if(son[u]) dfs2(son[u],r);
        for(int i=g[u];~i;i=next[i]) if(v[i]!=anc[u][0] && v[i] != son[u]) 
            dfs2(v[i],v[i]);
        ed[u]=vid;
    }
    
    int LCA(int a,int b) {
        if(dep[a]<dep[b]) swap(a,b);
        for(int h=maxh-1;h>=0;h--) if(dep[anc[a][h]]>=dep[b]) a=anc[a][h];
        if(a==b) return a;
        for(int h=maxh-1;h>=0;h--) 
            if(anc[a][h]!=anc[b][h]) {
                a=anc[a][h];
                b=anc[b][h];
            }
        return anc[a][0];
    }
    
    void alter(int x,int y,int v) {
        while(root[y]!=root[x]) {
            seg.change(1,st[root[y]],st[y],v);
            y=anc[root[y]][0];    
        }
        seg.change(1,st[x],st[y],v);
    }
    
    int ANC(int x,int k) {
        for(int h=0;h<maxh && k;h++,k>>=1) if(k&1) x=anc[x][h];
        return x;
    }
    
    void query(int id) {
        if(cap==id) printf("%d
    ",seg.query(1,1,n));
        else if(LCA(cap,id)==id) {
            int p=ANC(cap,dep[cap]-dep[id]-1);
            printf("%d
    ",min(seg.query(1,1,st[p]-1),seg.query(1,ed[p]+1,n)));
        }
        else printf("%d
    ",seg.query(1,st[id],ed[id]));
    }
    
    int main() {
        memset(g,-1,sizeof(g));
        scanf("%d%d",&n,&m);
        for(int i=1,a,b;i<n;i++) {
            scanf("%d%d",&a,&b);
            addedge(a,b);
        }
        anc[1][0]=1; cap=1;
        seg.build(1,1,n);
        dfs1(1);
        dfs2(1,1); 
        for(int i=1,a;i<=n;i++) {
            scanf("%d",&a);
            seg.change(1,st[i],st[i],a);    
        }
        scanf("%d",&cap);
        while(m--) {
            scanf("%d%d",&op,&x);
            if(op==1) cap=x;
            else if(op==2) {
                scanf("%d%d",&y,&val);
                int lca=LCA(x,y);
                alter(lca,x,val);
                alter(lca,y,val);
            }
            else query(x);
        }
        return 0;
    }
  • 相关阅读:
    dotNet MSIL中的一些不常见IL指令
    DNGuard HVM Release
    让 .Net 程序 脱离 .net framework框架 运行的方法
    [转载]Calling printf from C# The tale of the hidden __arglist keyword
    浅谈.Net脱壳中方法体的局部变量签名还原
    DNGuard HVM 2007 标准版正式发布
    DNGuard HVM RC2 发布(运行库更新)
    DNGuard HVM 2007 更新[20070823]
    .Net 保护中的 native compile 方式
    gridview输出到excel
  • 原文地址:https://www.cnblogs.com/invoid/p/5627686.html
Copyright © 2011-2022 走看看