zoukankan      html  css  js  c++  java
  • [BZOJ]3083: 遥远的国度

    题解:  

    方法一  我们采用树链剖分+线段树的做法

    对于操作2,3都是基本的树剖操作 唯一不同的是换根   对于换根我们分情况讨论 

    若查询的节点是当前根的lca节点 那么查询的是 查询节点在根-节点路径上的儿子节点的子树的补集 (可以手画一下

    若查询的节点不是lca那么直接查询原树的子树范围

    若查询的节点是当前根 则查询整颗子树  都是树剖基本操作

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <stack>
    #include <queue>
    #include <cmath>
    #include <set>
    #include <map>
    #define mp make_pair
    #define pb push_back
    #define pii pair<int,int>
    #define link(x) for(edge *j=h[x];j;j=j->next)
    #define inc(i,l,r) for(int i=l;i<=r;i++)
    #define dec(i,r,l) for(int i=r;i>=l;i--)
    const int MAXN=3e5+10;
    const double eps=1e-8;
    #define ll long long
    const int inf=2147483647;
    using namespace std;
    struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
    void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
    ll read(){
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    
    
    int fa[MAXN][21],dep[MAXN],son[MAXN],num[MAXN],n,m,a[MAXN];
    void dfs1(int x,int pre,int deep){
        dep[x]=deep+1;fa[x][0]=pre;num[x]=1;
        link(x){
    	if(j->t==pre)continue;
    	dfs1(j->t,x,deep+1);
    	num[x]+=num[j->t];
    	if(son[x]==-1||num[son[x]]<num[j->t])son[x]=j->t;
        }
    }
    
    int tp[MAXN],p[MAXN],cnt,fp[MAXN];
    void dfs2(int x,int td){
        tp[x]=td;p[x]=++cnt;fp[p[x]]=x;
        inc(i,1,20)fa[x][i]=fa[fa[x][i-1]][i-1];
        if(son[x]!=-1)dfs2(son[x],td);
        link(x){
    	if(j->t==fa[x][0]||j->t==son[x])continue;
    	dfs2(j->t,j->t);
        }
    }
    
    int Lca(int u,int v){
        int uu=tp[u];int vv=tp[v];
        while(uu!=vv){
    	if(dep[uu]<dep[vv])swap(uu,vv),swap(u,v);
    	u=fa[uu][0];uu=tp[u];
        }
        if(dep[u]>dep[v])swap(u,v);
        return u;
    }
    
    int Clca(int u,int v){
        dec(i,20,0){
    	if(dep[fa[u][i]]>dep[v])u=fa[u][i];
        }
        return u;
    }
    
    int minn[MAXN<<2],flag[MAXN<<2];
    void push(int x){
        if(flag[x]){
    	minn[x<<1]=minn[x<<1|1]=flag[x];
    	flag[x<<1]=flag[x<<1|1]=flag[x];
    	flag[x]=0;
        }
    }
    
    void up(int x){minn[x]=min(minn[x<<1],minn[x<<1|1]);}
    
    void built(int rt,int l,int r){
        flag[rt]=0;
        if(l==r){minn[rt]=a[fp[l]];return ;}
        int mid=(l+r)>>1;
        built(rt<<1,l,mid);
        built(rt<<1|1,mid+1,r);
        up(rt);
    }
    
    void update(int rt,int l,int r,int ql,int qr,int k){
        if(ql<=l&&r<=qr){flag[rt]=minn[rt]=k;return ;}
        int mid=(l+r)>>1;
        push(rt);
        if(ql<=mid)update(rt<<1,l,mid,ql,qr,k);
        if(qr>mid)update(rt<<1|1,mid+1,r,ql,qr,k);
        up(rt);
    }
    
    int ans;
    void query(int rt,int l,int r,int ql,int qr){
        if(ql>qr)return ;
        if(ql<=l&&r<=qr){ans=min(ans,minn[rt]);return ;}
        int mid=(l+r)>>1;
        push(rt);
        if(ql<=mid)query(rt<<1,l,mid,ql,qr);
        if(qr>mid)query(rt<<1|1,mid+1,r,ql,qr);
        up(rt);
    }
    
    void operator1(int u,int v,int k){
        int uu=tp[u];int vv=tp[v];
        while(uu!=vv){
    	if(dep[uu]<dep[vv])swap(u,v),swap(uu,vv);
    	update(1,1,n,p[uu],p[u],k);
    	u=fa[uu][0];uu=tp[u];
        }
        if(dep[u]>dep[v])swap(u,v);
        update(1,1,n,p[u],p[v],k);
    }
    
    int main(){
        minn[0]=inf;
        n=read();m=read();
        int u,v,k,op;
        inc(i,2,n)u=read(),v=read(),add(u,v),add(v,u);
        inc(i,1,n)a[i]=read(),son[i]=-1;
        dfs1(1,0,0);dfs2(1,1);
        built(1,1,n);
        int Rt=read();
        while(m--){
    	op=read();u=read();
    	if(op==1)Rt=u;
    	else if(op==2)v=read(),k=read(),operator1(u,v,k);
    	else{
    	    if(u==Rt){printf("%d
    ",minn[1]);continue;}
    	    int lca=Lca(Rt,u);
    	    if(lca!=u){
    		ans=inf;query(1,1,n,p[u],p[u]+num[u]-1);
    		printf("%d
    ",ans);
    	    }
    	    else{
    		v=Clca(Rt,u);
    		ans=inf;
    		query(1,1,n,1,p[v]-1);
    		query(1,1,n,p[v]+num[v],n);
    		printf("%d
    ",ans);
    	    }
    	}
        }
        return 0;
    }
    

     方法二: 采用LCT  用multiset维护虚子树信息然后解决即可   因为复杂度是O(nlog^2n)常数较大 在oj上没有通过 本地对拍AC  拿来练手

    #include <bits/stdc++.h>
    const int MAXN=1e5+10;
    #define ll long long
    const int inf=2147483647;
    using namespace std;
    ll readll(){
        ll 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;
    }
    int readint(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return f*x;
    }
    int ch[MAXN][2],minn[MAXN],key[MAXN],pre[MAXN],res[MAXN],flag[MAXN],cminn[MAXN];
    bool rt[MAXN];
    multiset<int>s[MAXN];
    void reverse(int r){
        if(!r) return ;
        swap(ch[r][0],ch[r][1]);
        res[r]^=1;
    }
    
    void Flag(int r,int t){
        if(!r)return ;
        key[r]=t;
        //cout<<t<<" "<<(*s[r].begin())<<endl;
        minn[r]=min(t,cminn[r]);
        flag[r]=t;
    }
    
    void push(int r){
        if(res[r]){
            reverse(ch[r][0]);
            reverse(ch[r][1]);
            res[r]^=1;
        }
        if(flag[r]){
            Flag(ch[r][0],flag[r]);
            Flag(ch[r][1],flag[r]);
            flag[r]=0;
        }
    }
    void up(int x){
        minn[x]=min(key[x],min(minn[ch[x][0]],minn[ch[x][1]]));
        cminn[x]=min(*s[x].begin(),cminn[ch[x][0]]);
        cminn[x]=min(cminn[x],cminn[ch[x][1]]);
    //  cout<<key[x]<<" "<<x<<" "<<minn[ch[x][0]]<<" "<<minn[ch[x][1]]<<endl;
        minn[x]=min(minn[x],*s[x].begin());
        //cout<<minn[x]<<endl;
    }
    void P(int r){
        if(!rt[r]) P(pre[r]);
        push(r);
    }
    void rotate(int x,int kind){
        int y=pre[x];
        pre[ch[x][kind]]=y;ch[y][!kind]=ch[x][kind];
        if(rt[y]) rt[y]=0,rt[x]=1;
        else ch[pre[y]][ch[pre[y]][1]==y]=x;
        pre[x]=pre[y];ch[x][kind]=y;pre[y]=x;
        up(y);
    }
    void splay(int x){
        P(x);
        while(!rt[x]){
            if(rt[pre[x]]) rotate(x,ch[pre[x]][0]==x);
            else{
                int y=pre[x];int kind=ch[pre[y]][0]==y;
                if(ch[y][kind]==x) rotate(x,!kind),rotate(x,kind);
                else rotate(y,kind),rotate(x,kind);
            }
        }
        up(x);
    }
    void access(int x){
        int y=0;
        while(x){
            splay(x);
            if(ch[x][1]) s[x].insert(minn[ch[x][1]]),rt[ch[x][1]]=1,pre[ch[x][1]]=x;
            if(y) rt[y]=0,s[x].erase(lower_bound(s[x].begin(),s[x].end(),minn[y]));
            ch[x][1]=y;
            up(x);
            y=x;x=pre[x];
        }
    }
    void mroot(int r){
        access(r);splay(r);
        reverse(r);
    }
    void update(int u,int v,int t){
        mroot(u);access(v);splay(v);
        //key[v]=t;
        Flag(v,t);
        //up(v);
        //cout<<minn[v]<<" "<<endl;
    }
    void Link(int u,int v){
        //cout<<minn[u]<<" "<<minn[v]<<" "<<u<<" "<<v<<endl;
        mroot(u);mroot(v);//cout<<minn[u]<<" "<<minn[v]<<endl;
        pre[u]=v;
     
        s[v].insert(minn[u]);
        up(v);
        //cout<<minn[v]<<endl;
    }
    int querty(int v){
        //cout<<v<<" "<<pre[v]<<endl;
        access(v);splay(v);
        //cout<<ch[v][0]<<" "<<ch[v][1]<<endl;
        //cout<<(*s[v].begin())<<endl;
        //cout<<key[v]<<endl;
        return min(key[v],(*s[v].begin()));
    }
    void newnode(int t){
        ch[t][0]=ch[t][1]=pre[t]=res[t]=0;rt[t]=1;
    }
    
    typedef struct Node{
        int x,y;
    }Node;
    Node que[MAXN];
    int main(){
        //ios::sync_with_stdio(false);
        int n,m;n=readint();m=readint();
        int f,vul;
        cminn[0]=key[0]=minn[0]=inf;
        //for(int i=1;i<=n;i++) newnode(i),s[i].insert(inf);
        for(int i=1;i<n;i++){
            que[i].x=readint();
            que[i].y=readint();
     //       f=readint();vul=readint();key[i]=minn[i]=vul;
            //cout<<key[i]<<" "<<minn[i]<<endl;
            //if(f==0) continue;
      //      Link(i,f);
        }
        for(int i=1;i<=n;i++)newnode(i),s[i].insert(inf),cminn[i]=inf,key[i]=minn[i]=readint();
        for(int i=1;i<n;i++)Link(que[i].x,que[i].y);
        int Rt=readint();
        //cout<<querty(3)<<endl;
        int op;int x,y,k;
        for(int i=1;i<=m;i++){
            //scanf(" %c",&ch);
            op=readint();
            if(op==1){
                x=readint();Rt=x;
                //x=readint();y=readint();update(x,y);
            }
            else if(op==2){
                x=readint();y=readint();k=readint();
                update(x,y,k);
                //x=readint();mroot(x);
            }
            else x=readint(),mroot(Rt),printf("%d
    ",querty(x));
            //for(int i=1;i<=n;i++) cout<<querty(i)<<" ";
        //  cout<<endl;
        }
        return 0;
    }
    

      

    3083: 遥远的国度

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 5121  Solved: 1484
    [Submit][Status][Discuss]

    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
    提示
    对于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。

     

  • 相关阅读:
    JS知识点
    JQuery知识点
    常见简单算法
    Html知识点
    Java基础_基本语法
    Java基础_Java概述
    VBA基础——循环语句
    VBA基础知识———常用语句
    VBA基础概念
    安全、结构良好的jQuery结构模板
  • 原文地址:https://www.cnblogs.com/wang9897/p/10350998.html
Copyright © 2011-2022 走看看