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

    链接

    感觉这个题思维难度并不高,问题给的很明确:

    1.换根

    2.路径修改

    3.子树最小值

    2和3都可以用树链剖分解决,所以只用思考问题1.

    如果老老实实换根,肯定 TLE 了。

    我们发现,不论怎么换根,树的整体形态不变,所以对问题2不会产生影响。

    而对问题3,思考可能有几种情况:

    //记 pek 为首都,city 为询问的子树

    //先以1为根 dfs一遍

    1.city在pek的子树中 (即 lca ( pek , city ) ==pek ),那么 city 这棵子树不会发生改变,正常输出。

    2.city与pek没什么关系 (即 lca ( pek , city ) ! =pek && lca ( pek , city ) ! = city ) ,那么 city 的子树也不会受到影响,正常输出。

    3.pek在city的子树中 (即 lca ( pek , city ) ==city ) , 那么换根以后,pek 所在的这一支儿子子树都成了 city 的祖先,所以扣掉这一棵儿子子树就可以了。

    怎么找这棵儿子子树?

    可以扫一遍儿子,根据dfs序 子树编号连续 的性质

    如果 x 在 y 的子树中,则 pos [ x ] >= in [ y ] && pos [ x ] <= out [ y ] ;

    那么挖掉这一块,原来的子树区间变成了两个,取个min,复杂度就加了个常数而已。

    就A了

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<string>
      4 #include<cstring>
      5 #define maxn 500005
      6 using namespace std;
      7 
      8 int n,m;
      9 
     10 int fa[maxn],dep[maxn],sz[maxn];
     11 
     12 struct node{
     13     int y,nxt;
     14 }e[maxn*2];
     15 int h[maxn],tot=0;
     16 inline void ad(int x,int y){
     17     ++tot;
     18     e[tot].y=y;e[tot].nxt=h[x];h[x]=tot;
     19 }
     20 //建树 
     21 int id=0;
     22 long long line[maxn];
     23 int pos[maxn],top[maxn],son[maxn];
     24 long long a[maxn];
     25 inline void dfs(int u,int f){
     26     fa[u]=f;
     27     dep[u]=dep[f]+1;
     28     sz[u]=1;
     29     for(int i=h[u],y;i;i=e[i].nxt){
     30         y=e[i].y;
     31         if(y!=f){
     32             dfs(y,u);
     33             sz[u]+=sz[y];
     34             if(sz[y]>sz[son[u]])
     35                 son[u]=y;
     36         }
     37     } 
     38 }
     39 inline void dfs2(int x,int tp){
     40     top[x]=tp;
     41     ++id;
     42     pos[x]=id;
     43     line[id]=a[x];
     44     if(son[x])dfs2(son[x],tp);
     45     for(int i=h[x],y;i;i=e[i].nxt){
     46         y=e[i].y;
     47         if(y!=fa[x]&&y!=son[x]){
     48             dfs2(y,y);
     49         }
     50     }
     51 }
     52 //树剖两遍dfs 
     53 struct tr{
     54     int l,r;
     55     long long mx,cg;
     56 }t[maxn<<2];
     57 inline void pushup(int k){
     58     t[k].mx=min(t[k<<1].mx,t[k<<1|1].mx);
     59 }
     60 inline void biu(int k,int l,int r){
     61     t[k].l=l;
     62     t[k].r=r;
     63     t[k].cg=0;
     64     if(l==r){
     65         t[k].mx=line[l];
     66         return ;
     67     }
     68     int mid=(l+r)>>1;
     69     biu(k<<1,l,mid);
     70     biu(k<<1|1,mid+1,r);
     71     pushup(k);
     72 }
     73 inline void pushd(int k){
     74     if(t[k].cg){
     75         t[k<<1].cg=t[k<<1].mx=t[k].cg;
     76         t[k<<1|1].cg=t[k<<1|1].mx=t[k].cg;
     77         t[k].cg=0;
     78     }
     79 }
     80 inline void change(int k,int x,int y,long long z){
     81     int l=t[k].l,r=t[k].r,mid=(l+r)>>1;
     82     if(l==x&&r==y){
     83         t[k].cg=z;
     84         t[k].mx=z;
     85         return ;
     86     }
     87     pushd(k);
     88     if(y<=mid)change(k<<1,x,y,z);
     89     else if(x>mid)change(k<<1|1,x,y,z);
     90     else{
     91         change(k<<1,x,mid,z);
     92         change(k<<1|1,mid+1,y,z);
     93     }
     94     pushup(k);
     95 }
     96 inline long long ask(int k,int x,int y){
     97     int l=t[k].l,r=t[k].r,mid=(l+r)>>1;
     98     if(l==x&&r==y)return t[k].mx;
     99     pushd(k);
    100     if(y<=mid)return ask(k<<1,x,y);
    101     else if(x>mid)return ask(k<<1|1,x,y);
    102     else return min(ask(k<<1,x,mid),ask(k<<1|1,mid+1,y));
    103 }
    104 //线段树 
    105 inline void change_path(int x,int y,long long z){
    106     while(top[x]!=top[y]){
    107         if(dep[top[x]]<dep[top[y]])swap(x,y);
    108         change(1,pos[top[x]],pos[x],z);
    109         x=fa[top[x]];
    110     }
    111     if(dep[x]<dep[y])swap(x,y);
    112     change(1,pos[y],pos[x],z);
    113 }
    114 inline int lca(int x,int y){
    115     while(top[x]!=top[y]){
    116         if(dep[top[x]]<dep[top[y]])swap(x,y);
    117         x=fa[top[x]];
    118     }
    119     return dep[x]<=dep[y]?x:y;
    120 }
    121 //树链剖分的应用 
    122 int main()
    123 {
    124     scanf("%d%d",&n,&m);
    125     int x,y;
    126     for(int i=1;i<n;i++){
    127         scanf("%d%d",&x,&y);
    128         ad(x,y);
    129         ad(y,x);
    130     }
    131     for(int i=1;i<=n;i++)
    132         scanf("%lld",&a[i]);
    133     dfs(1,1);
    134     dfs2(1,1);
    135     biu(1,1,n);
    136     int op;
    137     int city,p1,p2;
    138     long long v;
    139     int pek;
    140     int c;
    141     scanf("%d",&pek);
    142     for(int i=1;i<=m;i++){
    143         scanf("%d",&op);
    144         if(op==1){
    145             scanf("%d",&c);
    146             pek=c;continue;
    147         }//换根 
    148         else if(op==2){
    149             scanf("%d%d%lld",&p1,&p2,&v);
    150             change_path(p1,p2,v);
    151             continue;
    152         }//路径修改 
    153         else if(op==3){
    154             scanf("%d",&city);
    155             if(city==pek){
    156                 printf("%lld
    ",t[1].mx);
    157                 continue;
    158             }//如果是根直接输出 
    159             else{
    160                 int lc=lca(city,pek);
    161                 if(lc==city){
    162                     int ll,rr;
    163                     for(int j=h[city],y;j;j=e[j].nxt){
    164                         y=e[j].y;
    165                         if(pos[y]<=pos[pek]&&pos[y]+sz[y]-1>=pos[pek]){
    166                             ll=pos[y]-1;
    167                             rr=pos[y]+sz[y];
    168                             break;
    169                         }
    170                     }//找pek所在的儿子子树 
    171                     long long ans=10000000000;
    172                     if(rr<=n)
    173                         ans=min(ask(1,1,ll),ask(1,rr,n));
    174                     //这里rr可能是n+1,避免re,需要特判一下 
    175                     else ans=ask(1,1,ll);
    176                     printf("%lld
    ",ans);
    177                     continue;
    178                 }//情况3 
    179                 else
    180                     printf("%lld
    ",ask(1,pos[city],pos[city]+sz[city]-1));
    181                 //其他情况 
    182             }
    183         }
    184     }
    185 } 
    qwq
  • 相关阅读:
    linux安装日志切割程序
    Linux下安装JDK
    深入理解Java注解类型(@Annotation)
    23种设计模式--代理模式-Proxy
    23种设计模式--建造者模式-Builder Pattern
    23种设计模式--工厂模式-Factory Pattern
    23种设计模式
    Java集合框架学习笔记
    MySQL入门笔记(一)
    二进制运算基础
  • 原文地址:https://www.cnblogs.com/chiyo/p/10017463.html
Copyright © 2011-2022 走看看