【bzoj3083】遙遠的國度(樹鏈剖分+線段樹)
題目描述
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】遙遠的國度(樹鏈剖分+線段樹)