1. 程式人生 > >【bzoj3083】遙遠的國度(樹鏈剖分+線段樹)

【bzoj3083】遙遠的國度(樹鏈剖分+線段樹)

region ont lin names 一個點 輸入輸出格式 -- wap 操作數

題目描述

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<=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。

題解

  第一眼看過去覺得是LCT

  然後發現沒法維護子樹信息,決定每一個點開一棵平衡樹,後來發現空間要爆……

  於是好好學了一下正解

  首先查詢和修改路徑都是樹剖的基本操作這裏不提

  然後現在最重要的是換根操作咋整

  我們考慮一下,當前根與點$x$在原樹中的關系無非以下幾種:

  1.當前根就是點$x$——那麽直接輸出整棵樹答案就行了

  2.當前根在原樹中不在$x$的子樹內——那麽哪怕根換成了現在的根,$x$的子樹還是沒有變化,那麽我們可以直接去原來的子樹裏查詢

  3.當前根在原樹中在$x$的子樹內——那麽我們設當前根在$u$點的子樹$v$內,那麽所要求的答案就是整棵樹除去$v$這一棵子樹的答案。至於怎麽求$v$,可以從$root$往上跳重鏈,直到跳到$u$為止,那麽就是看它從哪一個$u$點的子節點跳過來的就好了

  因為讀入進來的時候路徑端點和更改的值弄錯了……而且忘記找$v$了……調了半天

  1 //minamoto
  2 #include<iostream>
  3 #include<cstdio>
  4 #define int unsigned int
  5 using namespace std;
  6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
  7 char buf[1<<21],*p1=buf,*p2=buf;
  8 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
  9 inline int read(){
 10     #define num ch-‘0‘
 11     char ch;bool flag=0;int res;
 12     while(!isdigit(ch=getc()))
 13     (ch==-)&&(flag=true);
 14     for(res=num;isdigit(ch=getc());res=res*10+num);
 15     (flag)&&(res=-res);
 16     #undef num
 17     return res;
 18 }
 19 char sr[1<<21],z[30];int C=-1,Z;
 20 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
 21 inline void print(int x){
 22     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
 23     while(z[++Z]=x%10+48,x/=10);
 24     while(sr[++C]=z[Z],--Z);sr[++C]=\n;
 25 }
 26 const int N=100005,inf=0xffffffff;
 27 int head[N],Next[N<<1],ver[N<<1],tot;
 28 int fa[N],dep[N],son[N],sz[N],top[N],ls[N],rs[N],cnt;
 29 int v[N],mn[N<<2],tag[N<<2];
 30 int n,m,rt;
 31 inline void add(int u,int v){
 32     ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
 33     ver[++tot]=u,Next[tot]=head[v],head[v]=tot;
 34 }
 35 void dfs1(int u){
 36     sz[u]=1,dep[u]=dep[fa[u]]+1;
 37     for(int i=head[u];i;i=Next[i]){
 38         int v=ver[i];
 39         if(v!=fa[u]){
 40             fa[v]=u,dfs1(v),sz[u]+=sz[v];
 41             if(sz[v]>sz[son[u]]) son[u]=v;
 42         }
 43     }
 44 }
 45 void dfs2(int u,int t){
 46     top[u]=t,ls[u]=++cnt;
 47     if(son[u]){
 48         dfs2(son[u],t);
 49         for(int i=head[u];i;i=Next[i]){
 50             int v=ver[i];
 51             if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
 52         }
 53     }
 54     rs[u]=cnt;
 55 }
 56 inline void pushup(int p){mn[p]=min(mn[p<<1],mn[p<<1|1]);}
 57 inline void pushdown(int p){
 58     if(tag[p])
 59     mn[p<<1]=mn[p<<1|1]=tag[p<<1]=tag[p<<1|1]=tag[p],tag[p]=0;
 60 }
 61 void build(int p,int l,int r){
 62     if(l==r) return (void)(mn[p]=v[l]);
 63     int mid=l+r>>1;
 64     build(p<<1,l,mid),build(p<<1|1,mid+1,r);
 65     pushup(p);
 66 }
 67 void update(int p,int l,int r,int ql,int qr,int x){
 68     if(ql<=l&&qr>=r) return (void)(mn[p]=tag[p]=x);
 69     pushdown(p);
 70     int mid=l+r>>1;
 71     if(ql<=mid) update(p<<1,l,mid,ql,qr,x);
 72     if(qr>mid) update(p<<1|1,mid+1,r,ql,qr,x);
 73     pushup(p);
 74 }
 75 int query(int p,int l,int r,int ql,int qr){
 76     if(ql<=l&&qr>=r) return mn[p];
 77     pushdown(p);
 78     int mid=l+r>>1,ans=inf;
 79     if(ql<=mid) cmin(ans,query(p<<1,l,mid,ql,qr));
 80     if(qr>mid) cmin(ans,query(p<<1|1,mid+1,r,ql,qr));
 81     return ans;
 82 }
 83 int find(int t,int u){
 84     while(top[u]!=top[t]){
 85         if(fa[top[u]]==t) return top[u];
 86         u=fa[top[u]];
 87     }
 88     return son[t];
 89 }
 90 void modify(int u,int v,int x){
 91     while(top[u]!=top[v]){
 92         if(dep[top[u]]<dep[top[v]]) swap(u,v);
 93         update(1,1,n,ls[top[u]],ls[u],x),u=fa[top[u]];
 94     }
 95     if(dep[u]>dep[v]) swap(u,v);
 96     update(1,1,n,ls[u],ls[v],x);
 97 }
 98 signed main(){
 99     //freopen("testdata.in","r",stdin);
100     n=read(),m=read();
101     for(int i=1;i<n;++i){
102         int u=read(),v=read();add(u,v);
103     }
104     dfs1(1),dfs2(1,1);
105     for(int i=1;i<=n;++i) v[ls[i]]=read();
106     build(1,1,n);
107     rt=read();
108     while(m--){
109         int opt=read(),x=read(),y,z;
110         switch(opt){
111             case 1:rt=x;break;
112             case 2:y=read(),z=read(),modify(x,y,z);break;
113             case 3:{
114                 if(ls[rt]==ls[x]) print(mn[1]);
115                 else if(ls[rt]<ls[x]||ls[rt]>rs[x]) print(query(1,1,n,ls[x],rs[x]));
116                 else{
117                     int res=inf,t=find(x,rt);
118                     if(ls[t]>1) cmin(res,query(1,1,n,1,ls[t]-1));
119                     if(rs[t]<n) cmin(res,query(1,1,n,rs[t]+1,n));
120                     print(res);
121                 }
122                 break;
123             }
124         }
125     }
126     Ot();
127     return 0;
128 }

【bzoj3083】遙遠的國度(樹鏈剖分+線段樹)