zoukankan      html  css  js  c++  java
  • BZOJ 3083 遥远的国度(树链剖分)

    3083: 遥远的国度

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 5003  Solved: 1434
    [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。

    HINT

     

    Source

    zhonghaoxi提供

    题解:

    这题有换根操作,但按照普通的思路我们可以发现,换根之后树的形态会有改变,每个节点的子树会发生改变,所以我们来分类讨论。

    修改链的操作不会发生改变,现在只考虑子树minn。为了方便,我们定义现在的换的“根节点”为root(但实际上树的根节点为1),子树根为x,黑圈标明查询范围;

    情况一   x=root,很显然此时应当查询整棵树。

     

    情况二 lca(root,x)!=x ,此时直接查询x的子树即可,与换根无关。

    情况三,lca(root,x)=x,此时我们应当查询与x相邻的节点中与root最近的点v在整棵树中的补集

    可以发现v一定在root到x的链上,且一定是x在这条链上的儿子,倍增法可以求得v

    BZOJ TLE也返回RE???  用普通树剖一直RE,用倍增就过了Orz.

    参考代码:

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define clr(a,b) memset(a,b,sizeof (a))
      4 #define PI acos(-1.0)
      5 typedef long long ll;
      6 const int maxn=2e5+10;
      7 const int INF=0x3f3f3f3f;
      8 /*首先有一个整数opt如果opt=1接下来有一个整数id代表把首都修改
      9 为id如果opt=2接下来有三个整数p1 p2 v代表将p1 p2路径上的所有
     10 城市的防御值修改为v如果opt=3接下来有一个整数 id代表询问以城
     11 市id为根的子树中的最小防御值*/
     12 int n,m,op,xx,yy,zz,a[maxn],head[maxn];
     13 int siz[maxn],son[maxn],fa[maxn],top[maxn],deep[maxn];
     14 int tid[maxn],rnk[maxn],f[maxn][20],cnt,tot;
     15 struct Edge{
     16     int v,nxt;
     17 } edge[maxn<<1];
     18 void addedge(int x,int y) 
     19 {
     20     edge[tot].v=y;
     21     edge[tot].nxt=head[x];
     22     head[x]=tot++;
     23 }
     24 
     25 inline void dfs1(int x)
     26 {
     27     siz[x]=1; 
     28     for(int i=1;i<=19;++i) { if((1<<i)<=deep[x]) f[x][i]=f[f[x][i-1]][i-1];else break;  }
     29     for(int i=head[x];~i;i=edge[i].nxt)
     30     {
     31         int v=edge[i].v;
     32         if(v!=fa[x]) 
     33         {
     34             fa[v]=f[v][0]=x;
     35             deep[v]=deep[x]+1;
     36             dfs1(v);
     37             siz[x]+=siz[v];
     38             if(son[x]==-1||siz[son[x]]<siz[v]) son[x]=v; 
     39         }
     40     }
     41 }
     42 
     43 inline void dfs2(int x,int tp)
     44 {
     45     tid[x]=++cnt;rnk[cnt]=x;top[x]=tp;
     46     if(son[x]==-1) return;
     47     dfs2(son[x],tp);
     48     for(int i=head[x];~i;i=edge[i].nxt)
     49     {
     50         int v=edge[i].v;
     51         if(v!=fa[x]&&v!=son[x]) dfs2(v,v);
     52     }
     53 
     54 }
     55 
     56 struct Tree{
     57     int l,r,min_num;
     58     int tag;
     59 } tree[maxn<<4];
     60 
     61 inline void pushup(int rt)
     62 {
     63     tree[rt].min_num=min(tree[rt<<1].min_num,tree[rt<<1|1].min_num);
     64 }
     65 inline void pushdown(int rt)
     66 {
     67     tree[rt<<1].tag=tree[rt<<1|1].tag=tree[rt].tag;
     68     tree[rt<<1].min_num=tree[rt<<1|1].min_num=tree[rt].tag;
     69     tree[rt].tag=-1;
     70 }
     71 
     72 inline void Build(int rt,int l,int r)
     73 {
     74     tree[rt].l=l,tree[rt].r=r;tree[rt].tag=-1;
     75     if(l==r){ tree[rt].min_num=a[rnk[l]]; return ;}
     76     int mid=l+r>>1;
     77     Build(rt<<1,l,mid);Build(rt<<1|1,mid+1,r);
     78     pushup(rt);
     79 }
     80 
     81 inline void Insert(int rt,int L,int R,int val)//1
     82 {
     83     if(tree[rt].l>=L&&tree[rt].r<=R){tree[rt].min_num=tree[rt].tag=val;return;}
     84     if(~tree[rt].tag) pushdown(rt);
     85     int mid=(tree[rt].l+tree[rt].r)>>1;
     86     if(R<=mid) Insert(rt<<1,L,R,val);
     87     else if(L>=mid+1) Insert(rt<<1|1,L,R,val); 
     88     else Insert(rt<<1,L,mid,val),Insert(rt<<1|1,mid+1,R,val);
     89     pushup(rt);
     90 }
     91 //1和2用倍增来把x~y的值变为val 
     92 inline void Update(int x,int y,int val)//2
     93 {
     94     int fx=top[x],fy=top[y];
     95     while(fx!=fy)
     96     {
     97         if(deep[fx]<deep[fy]) swap(x,y),swap(fx,fy);
     98         Insert(1,tid[fx],tid[x],val);
     99         x=fa[fx],fx=top[x];
    100     }
    101     if(deep[x]>deep[y]) swap(x,y);
    102     Insert(1,tid[x],tid[y],val);
    103 }
    104 
    105 inline int Query(int rt,int L,int R)
    106 {
    107     if(tree[rt].l>=L&&tree[rt].r<=R) return tree[rt].min_num;
    108     if(~tree[rt].tag) pushdown(rt);
    109     int mid=tree[rt].l+tree[rt].r>>1;
    110     if(R<=mid) return Query(rt<<1,L,R);
    111     else if(L>=mid+1) return Query(rt<<1|1,L,R);
    112     else return min(Query(rt<<1,L,mid),Query(rt<<1|1,mid+1,R));    
    113 } 
    114 
    115 inline int LCA(int x,int y)
    116 {
    117     int fx=top[x],fy=top[y];
    118     while(fx!=fy)
    119     {
    120         if(deep[fx]<deep[fy]) swap(x,y),swap(fx,fy);
    121         x=fa[fx],fx=top[x];
    122     }
    123     return deep[x]>deep[y] ? y:x;
    124 }
    125 
    126 inline void Init()
    127 {
    128     clr(head,-1);clr(son,-1);
    129     clr(f,0);cnt=0;tot=1;
    130 }
    131 int main()
    132 {
    133     Init();int root;deep[1]=1;
    134     scanf("%d%d",&n,&m);
    135     for(int i=1;i<n;++i) scanf("%d%d",&xx,&yy),addedge(xx,yy),addedge(yy,xx);
    136     for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    137     dfs1(1),dfs2(1,1);Build(1,1,n);
    138     scanf("%d",&root);
    139     while(m--)
    140     {
    141         scanf("%d%d",&op,&xx);
    142         if(op==1) root=xx;
    143         else if(op==2) { scanf("%d%d",&yy,&zz),Update(xx,yy,zz); }
    144         else
    145         {
    146             if(root==xx) { printf("%d
    ",tree[1].min_num);continue;}
    147             int lca=LCA(xx,root);
    148             if(xx!=lca) printf("%d
    ",Query(1,tid[xx],tid[xx]+siz[xx]-1));
    149             else
    150             {
    151                 int tmp=deep[root]-deep[xx]-1,ans=INF;yy=root;
    152                 for(int i=0;i<=19;++i) if((1<<i)&tmp) yy=f[yy][i];
    153                 if(tid[yy]>1) ans=Query(1,1,tid[yy]-1);
    154                 if(tid[yy]+siz[yy]<=n) ans=min(ans,Query(1,tid[yy]+siz[yy],n));
    155                 printf("%d
    ",ans);
    156             }
    157         }
    158     }
    159     return 0;
    160 }
    161 /*
    162 3 7
    163 1 2
    164 1 3
    165 1 2 3
    166 1
    167 3 1
    168 2 1 1 6
    169 3 1
    170 2 2 2 5
    171 3 1
    172 2 3 3 4
    173 3 1
    174 */
    View Code

      

  • 相关阅读:
    二级python两种不同处理方式统计字频
    二级python提纯文件中的原文(去掉小括号,注释等)
    二级python处理文件并计数
    二级python对字频统计
    matlab实现跨表自动对应标题填写数据
    用matlab对excel中数据选择性染色
    最短路径查找—Dijkstra算法
    BP实现函数拟合
    BP应用案例
    Matlab实现BP神经网络预测(附实例数据及代码)
  • 原文地址:https://www.cnblogs.com/csushl/p/9874160.html
Copyright © 2011-2022 走看看