SCUOJ4549-树链剖分(区间查询,区间更新,边权)
来源:互联网 发布:api管理 知乎 编辑:程序博客网 时间:2024/06/05 16:21
传送门:scu4559
Description
There is a king who is very rich, but he is very stingy. In his kingdom, there are many cities. He built many highways to connect all the cities. Buecause of his meanness, he would not build extra highways, that's to say, there is only one path between any two cities. After building all the highways, he set a high toll for each highway. But because of his greed, he sometimes will increase the tolls to get more benefits. Now the king wants to know the tolls between two cities.However he is a fool, so he asks you to help him calculate the answer.Input
The first line contains an integer T indicating the number of cases. (T < 20)For each case, the first line contains two integers N and M indicating the number of cities and the number of operations. (N <= 10^5, M <= 10^5)Then N-1 lines followed. Each line contains three integers a, b and c. It means there is a highway between city a and city b, and the toll is c. (1 <= a <= n, 1 <= b <= n, a <> b, 0 < c <= 10^5)Then M lines followed. Each line has one of two operations.The first operation is "ADD a b c". which means adding c to the toll of every highway between city a and city b. (0 < c <= 10^5)The second is "QUERY a b", which means querying the highway tolls between city a and city b.Output
Answer for each QUERY operation.Sample Input
15 31 2 11 3 22 4 32 5 4QUERY 1 2ADD 1 5 1QUERY 1 5Sample Output
17
第一道树链剖分入门题,,哎,,搞了两天,,真心菜,,树链剖分详见各路大神的博客
题目大意:
给你一个n个点的树,q次操作,每条边都有一个权值,有两种操作
1,QUERY x y 查询 x到y的路径上所有的边权和
2,ADD x y w 将x到y的路径上的所有边权加上 w
题目思路:
树链剖分+线段树模板
基于边权的区间查询和区间更新
AC代码:
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<vector>using namespace std;#define ll long long#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1const int maxn = 1e5+10;struct Tree{ int l,r; ll sum,c;}node[maxn*8]; //线段树struct nod{ int v,nex; ll w;}edge[maxn<<1]; //图;int head[maxn];int tim ; //记录编号ll val[maxn];int Size[maxn]; // 以x为根的子树节点个数int Top[maxn]; // 当前节点所在链的顶端节点int Son[maxn]; // 保存重儿子int Deep[maxn]; // 节点深度int Father[maxn]; // 保存父亲节点int Tid[maxn]; // 剖分后的新编号int Rank[maxn]; // 保存在线段树中的编号int n,m,e; //节点个数和边数// 初始化函数void init(){ tim = 0; e = 1; memset(head,-1,sizeof(head)); memset(Son,-1,sizeof(Son));}void add(int u,int v,ll w){ edge[e].v = v,edge[e].w = w,edge[e].nex = head[u],head[u]=e++;}// 记录所有的重边void dfs(int u,int father,int d){ Deep[u]=d; Father[u]=father; Size[u]=1; for(int i=head[u];~i;i=edge[i].nex) { int v = edge[i].v; if(v!=father) { val[v] = edge[i].w; dfs(v,u,d+1); Size[u]+=Size[v]; if(Son[u]==-1||Size[v]>Size[Son[u]]) Son[u]=v; } }}//重连边成重边void Create(int u,int top){ Top[u]=top; Tid[u]=++tim; Rank[Tid[u]] = u; if(Son[u]==-1)return ; Create(Son[u],top); for(int i=head[u];~i;i=edge[i].nex) { int v = edge[i].v; if(v!=Son[u]&&v!=Father[u]) Create(v,v); }}void BuildTree(int l,int r,int rt){ node[rt].l = l,node[rt].r = r; node[rt].c = 0; if(l==r) { node[rt].sum = val[Rank[l]]; return ; } int mid = (l+r)>>1; BuildTree(lson); BuildTree(rson); node[rt].sum = node[rt<<1].sum+node[rt<<1|1].sum;}void pushdown(int rt,ll m){ node[rt<<1].c+=node[rt].c; node[rt<<1|1].c+=node[rt].c; node[rt<<1].sum+=node[rt].c*(m-m/2); node[rt<<1|1].sum+=node[rt].c*(m/2); node[rt].c = 0;}ll quary(int l,int r,int rt) //区间查询{ if(l<=node[rt].l&&r>=node[rt].r)return node[rt].sum; if(node[rt].c)pushdown(rt,node[rt].r-node[rt].l+1ll); int mid = (node[rt].l+node[rt].r)>>1; ll res = 0; if(l<=mid)res+=quary(l,r,rt<<1); if(r>mid)res+=quary(l,r,rt<<1|1); return res;}void update(int l,int r,ll w,int rt) //区间更新{ if(l<=node[rt].l&&r>=node[rt].r) { node[rt].c+=w; node[rt].sum+=(node[rt].r-node[rt].l+1ll)*w; return ; } int mid = (node[rt].l+node[rt].r)>>1; if(node[rt].c)pushdown(rt,node[rt].r-node[rt].l+1ll); if(l<=mid)update(l,r,w,rt<<1); if(r>mid)update(l,r,w,rt<<1|1); node[rt].sum = node[rt<<1].sum+node[rt<<1|1].sum;}ll SUM(int x,int y){ ll res = 0; while(Top[x]!=Top[y]) { if(Deep[Top[x]]<Deep[Top[y]])swap(x,y); res+=quary(Tid[Top[x]],Tid[x],1); x = Father[Top[x]]; } if(x!=y) { if(Deep[x]<Deep[y])swap(x,y); res+=quary(Tid[y]+1,Tid[x],1); } return res;}void ADD(int x,int y,ll w){ while(Top[x]!=Top[y]) { if(Deep[Top[x]]<Deep[Top[y]])swap(x,y); update(Tid[Top[x]],Tid[x],w,1); x = Father[Top[x]]; } if(x!=y) { if(Deep[x]<Deep[y])swap(x,y); update(Tid[y]+1,Tid[x],w,1); }}int main(){ int t;cin>>t; while(t--) { init(); scanf("%d%d",&n,&m); for(int i=1;i<n;i++) { int x,y; ll w; scanf("%d%d%lld",&x,&y,&w); add(x,y,w); add(y,x,w); } dfs(1,1,1); Create(1,1); BuildTree(1,n,1); char s[10]; while(m--) { scanf("%s",s); int x,y; ll w; scanf("%d%d",&x,&y); if(s[0]=='Q') { printf("%lld\n",SUM(x,y)); } else { scanf("%lld",&w); ADD(x,y,w); } } } return 0;}
0 0
- SCUOJ4549-树链剖分(区间查询,区间更新,边权)
- poj 3237 树链剖分(区间更新,区间查询)
- HYSBZ 2243 树链剖分(区间更新,区间查询)较难
- 树状数组(区间更新区间查询)
- spoj375 树链剖分(单点更新,区间查询)
- poj3468 区间更新,区间查询
- POJ 3237 Tree(树链剖分 + 单点更新 + 区间更新 + 区间查询)
- nyoj228 士兵杀敌(五)(区间更新,区间查询)
- POJ-3468(线段树区间更新区间查询)
- hdu 5023(线段树区间更新+区间查询)
- codevs 4919 线段树:区间更新,区间查询(余数)
- HDU 3966(树链剖分 + 区间更新 + 点查询)
- HDU3966-树链剖分(区间更新,点查询)
- 线段树--区间更新区间查询--hdu4027
- 线段树区间查询区间更新
- 【树状数组 区间更新区间查询】code
- LightOj1080Binary Simulation(区间更新单点查询)
- 模式二(区间更新,单点查询)
- Android 屏幕适配方案
- git tag
- 机器之心深度研学社每周干货:2017年第13周
- Java的泛型
- android audioManager的简单使用
- SCUOJ4549-树链剖分(区间查询,区间更新,边权)
- 解决两个float类型的数值相减,精确度不准确的问题
- Spring拦截器使用
- 搜索——洛谷P1351 联合权值
- FATE
- 题目:打印出菱形图案
- php new self()是什么意思
- linux学习过程感悟
- Learning Spark笔记3-传递函数给Spark