zoukankan      html  css  js  c++  java
  • 洛谷P3979 遥远的国度

    题目描述

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

    问题是这样的:遥远的国度有(n)个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候(RapiD)会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。

    (RapiD)想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。

    由于(RapiD)无法解决这个问题,所以他拦住了(zcwwzdjn)希望他能帮忙。但(zcwwzdjn)还要追杀(sb)(zhx),所以这个重大的问题就被转交到了你的手上。

    输入输出格式

    输入格式:

    (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)为根的子树中的最小防御值。

    输出格式:

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

    输入输出样例

    输入样例#1:

    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
    

    输出`样例#1:

    1
    2
    3
    4
    

    说明

    对于(20\%)的数据,(n leq 1000,m leq 1000)

    对于另外(10\%)的数据,(n leq 100000,m leq 100000),保证修改为单点修改。

    对于另外(10\%)的数据,(n leq 100000,m leq 100000),保证树为一条链。

    对于另外(10\%)的数据,(n leq 100000)(m leq 100000),没有修改首都的操作。

    对于(100\%)的数据,(n leq 100000,m leq 100000)(0<)所有权值 (leq 2^31)

    思路:首先,第二和第三个操作都是树链剖分的基本操作,然后,这个题的难点在换根上,当然,可以用(LCT)实现……然而,我不会,所以就只能换一种思路,首先,换一次顶点(dfs)一次,建树一次,肯定会超时。那么我们来看,一个点成为根结点之后,只会影响到这个点到原来根结点那条路径上的点,所以,当查询一个点,跟当前点的(LCA)在这条链上时,我们就可以脑补一下,查询区间就是当前根到原根的路径上的原根的第一个儿子的子树的补集,然后剩余的两种情况,(LCA)是原根或当前根等于原根,直接(modify)即可。

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cctype>
    #define maxn 100007
    #define ls rt<<1
    #define rs rt<<1|1
    using namespace std;
    int n,m,head[maxn],son[maxn],size[maxn],d[maxn];
    int cnt,num,top[maxn],minn[maxn<<2],id[maxn],fa[maxn];
    int w[maxn],a[maxn],rt,lazy[maxn<<2];
    inline int qread() {
      char c=getchar();int num=0,f=1;
      for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
      for(;isdigit(c);c=getchar()) num=num*10+c-'0';
      return num*f;
    }
    struct node {
      int v,nxt;
    }e[maxn<<1];
    inline void ct(int u, int v) {
      e[++num].v=v;
      e[num].nxt=head[u];
      head[u]=num;
    }
    inline void pushup(int rt) {
      minn[rt]=min(minn[ls],minn[rs]);
    }
    void build(int rt, int l, int r) {
      if(l==r) {
        minn[rt]=a[l];
        return;
      }
      int mid=(l+r)>>1;
      build(ls,l,mid);
      build(rs,mid+1,r);
      pushup(rt);
    }
    inline void pushdown(int rt) {
      if(lazy[rt]) {
          minn[ls]=lazy[ls]=minn[rs]=lazy[rs]=lazy[rt];
          lazy[rt]=0;
      }
    }
    void modify(int rt, int l, int r, int L, int R, int val) {
      if(L>r||R<l) return;
      if(L<=l&&r<=R) {
        minn[rt]=val;
        lazy[rt]=val;
        return;
      }
      pushdown(rt);
      int mid=(l+r)>>1;
      modify(ls,l,mid,L,R,val),modify(rs,mid+1,r,L,R,val);
      pushup(rt);
    }
    int cmin(int rt, int l, int r, int L, int R) {
      if(L>r||R<l) return 0x7fffffff;
      if(L<=l&&r<=R) return minn[rt];
      int mid=(l+r)>>1;
      int minn=0x7fffffff;
      pushdown(rt);
      if(L<=mid) minn=min(minn,cmin(ls,l,mid,L,R));
      if(R>mid) minn=min(minn,cmin(rs,mid+1,r,L,R));
      return minn;
    }
    void dfs1(int u, int f) {
      size[u]=1;
      for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(v!=f) {
          d[v]=d[u]+1;
          fa[v]=u;
          dfs1(v,u);
          size[u]+=size[v];
          if(size[v]>size[son[u]]) son[u]=v;
        }
      }
    }
    void dfs2(int u, int t) {
      id[u]=++cnt;
      a[cnt]=w[u];
      top[u]=t;
      if(son[u]) dfs2(son[u],t);
      for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
      }
    }
    inline int lca(int x, int y) {
      int fx=top[x],fy=top[y];
      while(fx!=fy) {
        if(d[fx]<d[fy]) swap(x,y),swap(fx,fy);
        x=fa[fx],fx=top[x];
      }
      return d[x]>d[y]?y:x;
    }
    void cal(int x, int y, int val) {
      int fx=top[x],fy=top[y];
      while(fx!=fy) {
        if(d[fx]<d[fy]) swap(x,y),swap(fx,fy);
        modify(1,1,cnt,id[fx],id[x],val);
        x=fa[fx],fx=top[x];
      }
      if(id[x]>id[y]) swap(x,y);
      modify(1,1,cnt,id[x],id[y],val);
    }
    int main() {
      n=qread(),m=qread();
      for(int i=1,u,v;i<n;++i) {
        u=qread(),v=qread();
        ct(u,v);ct(v,u);
      }
      for(int i=1;i<=n;++i) w[i]=qread();
      rt=qread();
      dfs1(1,0);dfs2(1,1);build(1,1,n);
      for(int i=1,k,x,y,w;i<=m;++i) {
        k=qread();
        if(k==1) x=qread(),rt=x;
        if(k==2) x=qread(),y=qread(),w=qread(),cal(x,y,w);
        if(k==3) {
          x=qread();
          if(x==rt) {
            printf("%d
    ",minn[1]);
            continue;
          }
          int lc=lca(x,rt);
          if(lc!=x) {
            printf("%d
    ",cmin(1,1,n,id[x],id[x]+size[x]-1));
            continue;
          }
          if(lc==x) {
            int s;
            for(int i=head[x];i;i=e[i].nxt) {
              int v=e[i].v;
              if(id[v]<=id[rt]&&id[v]+size[v]-1>=id[rt]) {
                s=v;
                break;
              }
            }
            printf("%d
    ",min(cmin(1,1,n,1,id[s]-1),cmin(1,1,n,id[s]+size[s],n)));
          }
        }
      }
      return 0;
    }
    
  • 相关阅读:
    grep在指定类型的文件中查找字符 (转载)
    关于 android 中 postDelayed方法的讲解 (转载)
    linux下sprintf_s函数的替代(转载)
    两分钟彻底让你明白Android Activity生命周期(图文)!(转载)
    linux C之access函数(转载)
    Android.mk中call all-subdir-makefiles和call all-makefiles-under,$(LOCAL_PATH)的区别(转载)
    adb logcat 查看日志 (转载)
    Android 实用技巧 --- 命令godir (转载)
    emacs版本差异(转载)
    vim的visual可视模式(转载)
  • 原文地址:https://www.cnblogs.com/grcyh/p/10201395.html
Copyright © 2011-2022 走看看