P2590 [ZJOI2008]樹的統計
阿新 • • 發佈:2017-07-12
edge 一個點 i++ 沒有 out 輸出 ins chang 更改
輸出樣例#1:
題目描述
一棵樹上有n個節點,編號分別為1到n,每個節點都有一個權值w。
我們將以下面的形式來要求你對這棵樹完成一些操作:
I. CHANGE u t : 把結點u的權值改為t
II. QMAX u v: 詢問從點u到點v的路徑上的節點的最大權值
III. QSUM u v: 詢問從點u到點v的路徑上的節點的權值和
註意:從點u到點v的路徑上的節點包括u和v本身
輸入輸出格式
輸入格式:
輸入文件的第一行為一個整數n,表示節點的個數。
接下來n – 1行,每行2個整數a和b,表示節點a和節點b之間有一條邊相連。
接下來一行n個整數,第i個整數wi表示節點i的權值。
接下來1行,為一個整數q,表示操作的總數。
接下來q行,每行一個操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式給出。
輸出格式:
對於每個“QMAX”或者“QSUM”的操作,每行輸出一個整數表示要求輸出的結果。
輸入輸出樣例
輸入樣例#1:4 1 2 2 3 4 1 4 2 1 3 12 QMAX 3 4 QMAX 3 3 QMAX 3 2 QMAX 2 3 QSUM 3 4 QSUM 2 1 CHANGE 1 5 QMAX 3 4 CHANGE 3 6 QMAX 3 4 QMAX 2 4 QSUM 3 4
4 1 2 2 10 6 5 6 5 16
說明
對於100%的數據,保證1<=n<=30000,0<=q<=200000;中途操作中保證每個節點的權值w在-30000到30000之間。
裸的樹鏈剖分。
註意所有的值都要取最大或者最小。
有很小的負邊權!
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define ls k<<1 #define rs k<<1|1 using namespace std; const int MAXN=1000001; inline void read(int &n) { char c=‘+‘;int x=0;bool flag=0; while(c<‘0‘||c>‘9‘) {c=getchar();if(c==‘-‘)flag=1;} while(c>=‘0‘&&c<=‘9‘) {x=(x<<1)+(x<<3)+c-48,c=getchar();} flag==1?n=-x:n=x; } int n; int a[MAXN]; int fa[MAXN];// 每一個節點的父親節點 int deep[MAXN];// 每一個節點的深度 int top[MAXN];// 重鏈上的頂節點 int son[MAXN];// 每一個點的重兒子 int size[MAXN];// 子節點的數量 int pos[MAXN];// 劃分輕重鏈之後的編號 int tot;// 總結點的數量 struct node { int l,r,maxn,sum; }tree[MAXN]; struct EDGE { int u,v,nxt; }edge[MAXN]; int head[MAXN]; int num=1; //int nowmax=-1; int nowsum=0; void update(int k) { tree[k].maxn=max(tree[ls].maxn,tree[rs].maxn); tree[k].sum=(tree[ls].sum+tree[rs].sum); } void add_edge(int x,int y) { edge[num].u=x; edge[num].v=y; edge[num].nxt=head[x]; head[x]=num++; } int dfs1(int now,int nowfa,int nowdeep) { deep[now]=nowdeep; fa[now]=nowfa; size[now]=1; for(int i=head[now];i!=-1;i=edge[i].nxt) { if(edge[i].v!=nowfa) { dfs1(edge[i].v,now,nowdeep+1); size[now]+=size[edge[i].v]; if(son[now]==-1||size[edge[i].v]>size[son[now]]) son[now]=edge[i].v; } } } void dfs2(int now,int nowid) { tot++; pos[now]=tot;//更改當前節點的編號 top[now]=nowid; if(!son[now])// 沒有重兒子 return ; dfs2(son[now],nowid);// 在一條重鏈上 for(int i=head[now];i!=-1;i=edge[i].nxt) if(deep[edge[i].v]>deep[edge[i].u]&&edge[i].v!=son[edge[i].u]) dfs2(edge[i].v,edge[i].v);//自己和自己一條重鏈 return ; } void build_tree(int k,int ll,int rr) { tree[k].l=ll;tree[k].r=rr; if(tree[k].l==tree[k].r) { tree[k].maxn=tree[k].sum=0; return ; } int mid=(ll+rr)>>1; build_tree(ls,ll,mid); build_tree(rs,mid+1,rr); update(k); } void insert(int k,int pos,int val) { if(tree[k].l==tree[k].r) { tree[k].maxn=tree[k].sum=val; return ; } int mid=(tree[k].l+tree[k].r)>>1; if(pos<=mid) insert(ls,pos,val); if(pos>mid) insert(rs,pos,val); update(k); } int querymax(int k,int ll,int rr) { if(ll<=tree[k].l&&tree[k].r<=rr) return tree[k].maxn; int mid=(tree[k].l+tree[k].r)>>1,nowmax=-1; if(ll<=mid) nowmax=max(nowmax,querymax(ls,ll,rr)); if(rr>mid) nowmax=max(nowmax,querymax(rs,ll,rr)); return nowmax; } int askmax(int u,int v) { int ans=-0x7ffff; while(top[u]!=top[v])//不在一條重鏈上 { if(deep[top[u]]<deep[top[v]]) swap(u,v); ans=max(ans,querymax(1,pos[top[u]],pos[u])); u=fa[top[u]]; } if(pos[u]>pos[v]) swap(u,v); ans=max(ans,querymax(1,pos[u],pos[v])); return ans; } int querysum(int k,int ll,int rr) { if(ll<=tree[k].l&&tree[k].r<=rr) return tree[k].sum; int mid=(tree[k].l+tree[k].r)>>1,nowsum=0; if(ll<=mid) nowsum+=querysum(ls,ll,rr); if(rr>mid) nowsum+=querysum(rs,ll,rr); return nowsum; } int asksum(int u,int v) { int ans=0; while(top[u]!=top[v]) { if(deep[top[u]]<deep[top[v]]) swap(u,v); ans+=querysum(1,pos[top[u]],pos[u]); u=fa[top[u]]; } if(pos[u]>pos[v]) swap(u,v); ans+=querysum(1,pos[u],pos[v]); return ans; } int main() { ///freopen("bzoj_1036.in","r",stdin); //freopen("bzoj_1036.out","w",stdout); read(n); memset(head,-1,sizeof(head)); //memset(son,-1,sizeof(son)); for(int i=1;i<=n-1;i++) { int x,y; read(x);read(y); add_edge(x,y); add_edge(y,x); } for(int i=1;i<=n;i++) read(a[i]); dfs1(1,0,0); dfs2(1,1); build_tree(1,1,n); for(int i=1;i<=n;i++) insert(1,pos[i],a[i]); int q; read(q); for(int i=1;i<=q;i++) { string s; cin>>s; if(s[1]==‘H‘)// 修改 { int p,v; read(p);read(v); a[p]=v; insert(1,pos[p],v); } else if(s[1]==‘M‘)// 最大值 { int l,r; read(l);read(r); printf("%d\n",askmax(l,r)); } else//求和 { int l,r; read(l);read(r); printf("%d\n",asksum(l,r)); } } return 0; }
P2590 [ZJOI2008]樹的統計