【codevs3306】水果姐逛水果街Ⅲ 树链剖分
2016-01-07 08:43
429 查看
题目描述 Description
连续两天都没有被cgh难倒,水果姐心情很不错,第三天又来逛水果街。今天cgh早早就来到了水果街等水果姐,因为他带来了帮手cys。cgh的魔法是把水果街变成树结构,而cys的魔法是瞬间改变某家店的水果价格。一边问一边改,绝不给水果姐思考的时间!
同样还是n家水果店,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样。
cgh和cys一共有m个操作。
操作的格式为
0 x y 获 1 x y
如果操作类型是0,表示cys把第x家店的价格改为y
如果操作类型是1,则表示要求水果姐从第x家店出发到第y家店,途中只能选一家店买一个水果,然后选一家店(可以是同一家店,但不能往回走)卖出去。并且输出最多可以赚多少钱。
这题是给天牛做的。
输入描述 Input Description
第一行n,表示有n家店下来n个正整数,表示每家店一个苹果的价格。
下来n-1行,每行两个整数x,y,表示第x家店和第y家店有一条边。
下来一个整数m,表示下来有m个操作。
下来有m行,每行三个整数,表示一次操作。
输出描述 Output Description
每行对应一个1类型的操作,输出一个整数,表示面对cgh的每次询问,水果姐最多可以赚到多少钱。样例输入 Sample Input
4 16 5 1 15 1 2 1 3 2 4 3 1 3 4 0 3 17 1 4 3
样例输出 Sample Output
15 12
数据范围及提示 Data Size & Hint
0<=苹果的价格<=10^80 < n<=2*10^5
0 < m<=10^5
思路和前两个:水果姐逛水果街Ⅰ和水果姐逛水果街Ⅱ思路差不多。
重点是查询答案的时候不要写反顺序!!!
挺有意思的树剖裸题。
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int SZ = 1000010; const int INF = 1000000010; int head[SZ],nxt[SZ],to[SZ],tot = 0; int num[SZ]; void build_edge(int f,int t) { to[++ tot] = t; nxt[tot] = head[f]; head[f] = tot; } int sz[SZ],fa[SZ],son[SZ],top[SZ],inseg[SZ],intree[SZ],deep[SZ]; void dfs_1(int u,int f) { sz[u] = 1; fa[u] = f; deep[u] = deep[f] + 1; for(int i = head[u];i;i = nxt[i]) { int v = to[i]; if(v == f) continue; dfs_1(v,u); sz[u] += sz[v]; if(!son[u] || sz[son[u]] < sz[v]) son[u] = v; } } int totp = 0; void dfs_2(int u,int tp) { top[u] = tp; inseg[u] = ++ totp; intree[totp] = u; if(!son[u]) return ; dfs_2(son[u],tp); for(int i = head[u];i;i = nxt[i]) { int v = to[i]; if(v == fa[u] || v == son[u]) continue; dfs_2(v,v); } } struct segment{ int l,r; int lans,rans,maxn,minn; }tree[SZ << 2]; void update(int p) { int lch = p << 1,rch = p << 1 | 1; tree[p].maxn = max(tree[lch].maxn,tree[rch].maxn); tree[p].minn = min(tree[lch].minn,tree[rch].minn); tree[p].lans = max(max(tree[lch].lans,tree[rch].lans),tree[rch].maxn - tree[lch].minn); tree[p].rans = max(max(tree[lch].rans,tree[rch].rans),tree[lch].maxn - tree[rch].minn); } void build_seg(int p,int l,int r) { tree[p].l = l; tree[p].r = r; if(l == r) { tree[p].maxn = tree[p].minn = num[intree[l]]; return ; } int mid = (l + r) >> 1; build_seg(p << 1,l,mid); build_seg(p << 1 | 1,mid + 1,r); update(p); } int ask_min(int p,int l,int r) { if(l <= tree[p].l && tree[p].r <= r) return tree[p].minn; int mid = (tree[p].l + tree[p].r) >> 1; int ans = INF; if(l <= mid) ans = min(ans,ask_min(p << 1,l,r)); if(mid < r) ans = min(ans,ask_min(p << 1 | 1,l,r)); return ans; } int ask_max(int p,int l,int r) { if(l <= tree[p].l && tree[p].r <= r) return tree[p].maxn; int mid = (tree[p].l + tree[p].r) >> 1; int ans = -INF; if(l <= mid) ans = max(ans,ask_max(p << 1,l,r)); if(mid < r) ans = max(ans,ask_max(p << 1 | 1,l,r)); return ans; } int ask_lans(int p,int l,int r) { if(l <= tree[p].l && tree[p].r <= r) return tree[p].lans; int mid = (tree[p].l + tree[p].r) >> 1; int ans = -INF; if(l <= mid && mid < r) ans = max(ans,ask_max(1,mid + 1,r) - ask_min(1,l,mid)); if(l <= mid) ans = max(ans,ask_lans(p << 1,l,r)); if(mid < r) ans = max(ans,ask_lans(p << 1 | 1,l,r)); return ans; } int ask_rans(int p,int l,int r) { if(l <= tree[p].l && tree[p].r <= r) return tree[p].rans; int mid = (tree[p].l + tree[p].r) >> 1; int ans = -INF; if(l <= mid && mid < r) ans = max(ans,ask_max(1,l,mid) - ask_min(1,mid + 1,r)); if(l <= mid) ans = max(ans,ask_rans(p << 1,l,r)); if(mid < r) ans = max(ans,ask_rans(p << 1 | 1,l,r)); return ans; } void change(int p,int pos,int d) { if(tree[p].l == tree[p].r) { tree[p].maxn = tree[p].minn = d; return ; } int mid = (tree[p].l + tree[p].r) >> 1; if(pos <= mid) change(p << 1,pos,d); else change(p << 1 | 1,pos,d); update(p); } int find_ans(int x,int y) { if(inseg[x] < inseg[y]) return ask_lans(1,inseg[x],inseg[y]); else return ask_rans(1,inseg[y],inseg[x]); } int find_max(int x,int y) { if(inseg[x] < inseg[y]) return ask_max(1,inseg[x],inseg[y]); else return ask_max(1,inseg[y],inseg[x]); } int find_min(int x,int y) { if(inseg[x] < inseg[y]) return ask_min(1,inseg[x],inseg[y]); else return ask_min(1,inseg[y],inseg[x]); } int ask(int x,int y) { int fx = top[x],fy = top[y]; int ans = 0,maxn = -INF,minn = INF; while(fx != fy) { if(deep[fx] > deep[fy]) { ans = max(ans,find_ans(x,fx)); minn = min(minn,find_min(x,fx)); ans = max(ans,maxn - minn); x = fa[fx]; fx = top[x]; } else { ans = max(ans,find_ans(fy,y)); maxn = max(maxn,find_max(fy,y)); ans = max(ans,maxn - minn); y = fa[fy]; fy = top[y]; } // cout<<fx<<" "<<x<<" "<<fy<<" "<<y<<" "<<maxn<<" "<<minn<<" "<<ans<<endl; } ans = max(ans,find_ans(x,y)); ans = max(ans,max(find_max(x,y) - minn,maxn - find_min(x,y))); // printf("%d %d\n",maxn,minn); return ans; } int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); int n; scanf("%d",&n); for(int i = 1;i <= n;i ++) { scanf("%d",&num[i]); } for(int i = 1;i <= n - 1;i ++) { int a,b; scanf("%d%d",&a,&b); build_edge(a,b); build_edge(b,a); } dfs_1(1,0); dfs_2(1,1); build_seg(1,1,n); int m; scanf("%d",&m); while(m --) { int opt,x,y; scanf("%d%d%d",&opt,&x,&y); if(opt) printf("%d\n",ask(x,y)); else change(1,inseg[x],y); /* for(int i = 1;i <= n;i ++) printf("%d ",ask_max(1,inseg[i],inseg[i])inseg[i]); puts("");*/ } return 0; } /* 11 92 84 39 31 19 18 96 10 54 76 98 2 1 3 1 4 1 5 1 6 3 7 1 8 3 9 1 10 2 11 5 1 1 4 11 */
相关文章推荐
- Android异步线程
- NSString作业2:取出字符串“123-456-789-000”中的数字部分,组成一个新的字符串输出
- 奇异值分解(SVD)原理详解及推导
- TextView排版问题解决
- 优化
- JSP内置对象详解
- vShield Manager5.5.4 防毒系统异常解决方案
- vShield Manager5.5.4 防毒系统异常解决方案
- NSString作业1:求字符串“158”和“39”按十进制数值做差后的结果,以字符串形式输出
- javascript类型系统 Window对象学习笔记
- 2015年十大黑客测试工具你认识几个?
- 持续集成学好jenkins之内置命令
- 北京Uber优步司机奖励政策(1月7日)
- python基础知识——编码
- 在 Ubuntu 15.10 上为单个网卡设置多个 IP 地址
- 判断Struts2的Get/Post请求
- 如何打造测试工程师精英团队?
- var和dynamic的区别及如何正确使用dynamic ?
- 滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(1月7日)
- Linux下查看CPU使用情况