【BZOJ1036】[ZJOI2008]树的统计Count
1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 15468 Solved: 6297
[Submit][Status][Discuss]
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
Input
输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有
一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作
的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
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
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
Sample Output
4
1
2
2
10
6
5
6
5
16
1
2
2
10
6
5
6
5
16
HINT
树链剖分+线段树裸题
操作1:修改dfs序线段树上某点的值
操作2:查询dfs序区间和
操作3:查询dfs序区间max
贴个板子在这
/************************************************************** Problem: 1036 User: redwind Language: C++ Result: Accepted Time:2268 ms Memory:6844 kb ****************************************************************/ /*To The End Of The Galaxy*/ #include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<algorithm> #include<queue> #include<iomanip> #include<stack> #include<map> #include<set> #include<cmath> #define debug(x) cerr<<#x<<"="<<x<<endl #define INF 0x7f7f7f7f #define llINF 0x7fffffffffffll using namespace std; typedef pair<int,int> pii; typedef long long ll; inline int init() { int now=0,ju=1;char c;bool flag=false; while(1) { c=getchar(); if(c=='-')ju=-1; else if(c>='0'&&c<='9') { now=now*10+c-'0'; flag=true; } else if(flag)return now*ju; } } inline long long llinit() { long long now=0,ju=1;char c;bool flag=false; while(1) { c=getchar(); if(c=='-')ju=-1; else if(c>='0'&&c<='9') { now=now*10+c-'0'; flag=true; } else if(flag)return now*ju; } } struct segment { int l,r; int sum,max; }tree[120004]; struct edge { int from,to,val,pre; }Edge[60004]; int dfs_time,cnt=0; int size[30005],head[30004],son[30005],top[30005],fa[30005],depth[30005],dfn[30005],rank[30005]; void predfs(int now,int f,int d) { depth[now]=d; fa[now]=f; size[now]++; for(int j=head[now];j;j=Edge[j].pre) { if(Edge[j].to!=f) { predfs(Edge[j].to,now,d+1); size[now]+=size[Edge[j].to]; if(!son[now]||size[Edge[j].to]>=size[son[now]]) { son[now]=Edge[j].to; } } } return; } void nextdfs(int now,int tmp) { top[now]=tmp; dfn[now]=++dfs_time; rank[dfn[now]]=tmp; if(!son[now])return; nextdfs(son[now],tmp); for(int j=head[now];j;j=Edge[j].pre) { if(Edge[j].to!=fa[now]&&Edge[j].to!=son[now]) { nextdfs(Edge[j].to,Edge[j].to); } } return ; } inline void addedge(int from,int to,int val) { ++cnt; Edge[cnt]=((edge){from,to,val,head[from]}); head[from]=cnt; } int n; #define lson (now<<1) #define rson (now<<1|1) #define mid ((l+r)>>1) void build(int l,int r,int now) { tree[now].l=l;tree[now].r=r; if(l==r)return; build(l,mid,lson); build(mid+1,r,rson); } void Modify(int l,int r,int x,int pos,int now) { tree[now].l=l;tree[now].r=r; if(l==r) { tree[now].sum=tree[now].max=x; } else { if(pos<=mid)Modify(l,mid,x,pos,lson); else Modify(mid+1,r,x,pos,rson); tree[now].max=max(tree[lson].max,tree[rson].max); tree[now].sum=tree[lson].sum+tree[rson].sum; } return; } int QuerySum(int l,int r,int x,int y,int now) { if(l==x&&r==y) { return tree[now].sum; } else { if(y<=mid)return QuerySum(l,mid,x,y,lson); else if(x>mid)return QuerySum(mid+1,r,x,y,rson); else return QuerySum(l,mid,x,mid,lson)+QuerySum(mid+1,r,mid+1,y,rson); } } int QueryMax(int l,int r,int x,int y,int now) { if(l==x&&r==y) { return tree[now].max; } else { if(y<=mid)return QueryMax(l,mid,x,y,lson); else if(x>mid)return QueryMax(mid+1,r,x,y,rson); else return max(QueryMax(l,mid,x,mid,lson),QueryMax(mid+1,r,mid+1,y,rson)); } } int SolveSum(int x,int y) { int sum=0; while(top[x]!=top[y]) { if(depth[top[x]]<depth[top[y]])swap(x,y); sum+=QuerySum(1,n,dfn[top[x]],dfn[x],1); x=fa[top[x]]; } if(dfn[x]>dfn[y])swap(x,y); sum+=QuerySum(1,n,dfn[x],dfn[y],1); return sum; } int SolveMax(int x,int y) { int Max=-INF; while(top[x]!=top[y]) { if(depth[top[x]]<depth[top[y]])swap(x,y); Max=max(Max,QueryMax(1,n,dfn[top[x]],dfn[x],1)); x=fa[top[x]]; } if(dfn[x]>dfn[y])swap(x,y); Max=max(Max,QueryMax(1,n,dfn[x],dfn[y],1)); return Max; } int main() { char type[12]; int q; int a,b; n=init(); for(int i=1;i<n;i++) { a=init();b=init(); addedge(a,b,1); addedge(b,a,1); } predfs(1,0,1); nextdfs(1,1); for(int i=1;i<=n;i++) { a=init(); Modify(1,n,a,dfn[i],1); } q=init(); for(int i=1;i<=q;i++) { scanf("%s",type+1); if(strcmp(type+1,"QSUM")==0) { a=init();b=init(); printf("%d\n",SolveSum(a,b)); } else if(strcmp(type+1,"QMAX")==0) { a=init();b=init(); printf("%d\n",SolveMax(a,b)); } else { a=init();b=init(); Modify(1,n,b,dfn[a],1); } } return 0;