题目:维护一个树,支持修改边长,查询任意两点间距离。

思路:学习了一下树链剖分,还是看了一阵子才看懂的(大概两个多小时orz。。。)其实总的来说并不是很难,主要是数组比较多,然后看的那篇博客大概是为了压缩代码写得比较紧凑所以看的不是很明白。树链剖分的比较有技巧性的地方是查询,如果在一条轻链上,每次往上一条边,如果是在重链上,就是区间查询。树链剖分保证任意路径上的重链和轻链条数是logn的,所以总的复杂度就是logn的。这个题是单点更新,所以线段树方面没什么难度。

/*
*@author:  Cwind
*http://www.cnblogs.com/Cw-trip/
*/
#include <bits/stdc++.h>
#define pb push_back
#define PB pop_back
#define bk back()
#define se second
#define fs first
#define IINF (1<<29)
#define sq(x) (x)*(x)
#define eps 0.000000001
#define clr(x) memset((x),0,sizeof (x))
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;/////Segment Tree
const int maxp=1e5;
const int maxv=1e4+300;
struct Node {int l,r;int val;Node *ch[2];
}pool[maxp];
int ph=0;
inline Node *newNode(){Node *n=&pool[ph++];n->val=0;return n;
}
void seg_build(Node *n,int l,int r){n->l=l,n->r=r;if(r-l<=1) return;int mid=(r+l)/2;n->ch[0]=newNode();n->ch[1]=newNode();seg_build(n->ch[0],l,mid);seg_build(n->ch[1],mid,r);
}
void seg_update(Node *n,int a,int b,int x){int l=n->l,r=n->r;if(l>=b||r<=a) return;if(r-l<=1){n->val=x;return;}seg_update(n->ch[0],a,b,x);seg_update(n->ch[1],a,b,x);n->val=max(n->ch[0]->val,n->ch[1]->val);
}
int seg_query(Node *n,int a,int b){int l=n->l,r=n->r;if(l>=b||r<=a) return 0;if(l>=a&&r<=b) return n->val;return max(seg_query(n->ch[0],a,b),seg_query(n->ch[1],a,b));
}
Node *root;
void seg_init(){ph=0;root=newNode();
}///Tree Cut
struct EDGE{int to,d;int id;EDGE(int to,int d,int id):to(to),d(d),id(id){}
};
vector<EDGE> G[maxv];
int fa[maxv],dep[maxv],siz[maxv],son[maxv],top[maxv],w[maxv],itow[maxv],sone[maxv];
void dfs1(int v,int d,int f=-1){dep[v]=d;fa[v]=f;siz[v]=1;int maxs=0;son[v]=0;for(int i=0;i<G[v].size();i++){EDGE &e=G[v][i];if(e.to==f) continue;dfs1(e.to,d+1,v);siz[v]+=siz[e.to];if(siz[e.to]>maxs){son[v]=e.to;maxs=siz[e.to];sone[v]=e.id;}}
}
int dfsn=0;
int dd[maxv];
void dfs2(int v,int ff,int from){w[v]=dfsn++;itow[from]=w[v];if(ff==-1) top[v]=v;else top[v]=top[ff];if(son[v])dfs2(son[v],v,sone[v]);for(int i=0;i<G[v].size();i++){EDGE &e=G[v][i];if(e.to==fa[v]||e.to==son[v]) continue;dfs2(e.to,-1,e.id);}
}
int T,N;
void build_tree(){for(int i=1;i<N;i++){seg_update(root,itow[i],itow[i]+1,dd[i]);}
}int Query(int a,int b){int f1=top[a],f2=top[b],ans=0;while(f1!=f2){if(dep[f1]>dep[f2]) swap(a,b),swap(f1,f2);ans=max(ans,seg_query(root,w[f2],w[b]+1));b=fa[f2];f2=top[b];}if(a==b) return ans;if(dep[a]>dep[b]) swap(a,b);ans=max(ans,seg_query(root,w[a]+1,w[b]+1));return ans;
}
char r[maxv];
int main(){freopen("/home/files/CppFiles/in","r",stdin);//freopen("defense.in","r",stdin);//freopen("defense.out","w",stdout);cin>>T;while(T--){cin>>N;for(int i=1;i<=N;i++) G[i].clear();dfsn=0;seg_init();seg_build(root,1,N);for(int i=1;i<=N-1;i++){int a,b,c;scanf("%d%d%d",&a,&b,&c);G[a].pb(EDGE(b,c,i));G[b].pb(EDGE(a,c,i));dd[i]=c;}dfs1(1,0);dfs2(1,-1,0);seg_build(root,1,N);build_tree();for(;;){scanf("%s",r);if(r[0]=='D') break;if(r[0]=='C'){int a,b;scanf("%d%d",&a,&b);seg_update(root,itow[a],itow[a]+1,b);}else{int a,b;scanf("%d%d",&a,&b);printf("%d\n",Query(a,b));}}}return 0;
}

View Code

ps:t了,差点开始怀疑是线段树写挫了。。结果是死循环了。。。

hdu3966

题目:维护一棵树上的点权,给某两点间的路径上的所有点加上权值x,询问某个点的点权。

思路:由于是直接询问点,所以实际上比spoj的那道题好写,区间和直接用bit维护一下就好了。

/*
*@author:  Cwind
*http://www.cnblogs.com/Cw-trip/
*/
#include <bits/stdc++.h>
#define pb push_back
#define PB pop_back
#define bk back()
#define se second
#define fs first
#define IINF (1<<29)
#define sq(x) (x)*(x)
#define eps 0.000000001
#define clr(x) memset((x),0,sizeof (x))
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;const int maxn=5e4+300;
int N,M,O;
int a[maxn];
vector<int> G[maxn];
/////Tree Cut
int fa[maxn],dep[maxn],son[maxn],top[maxn],siz[maxn],tw[maxn];
void dfs1(int v,int d=0,int f=-1){fa[v]=f;siz[v]=1;dep[v]=d;son[v]=0;int ma=0;for(int i=0;i<G[v].size();i++){int u=G[v][i];if(u==f) continue;dfs1(u,d+1,v);siz[v]+=siz[u];if(siz[u]>ma){ma=siz[u];son[v]=u;}}
}
int dfsn=0;
void dfs2(int v){if(fa[v]==-1) top[v]=v;tw[v]=++dfsn;if(son[v]){top[son[v]]=top[v];dfs2(son[v]);}for(int i=0;i<G[v].size();i++){int u=G[v][i];if(u==fa[v]||u==son[v]) continue;top[u]=u;dfs2(u);}
}
/BIT
const int maxB=maxn*2;
struct BIT{int a[maxB],b[maxB];void clear(){memset(a,0,sizeof a);memset(b,0,sizeof b);}void add(int *A,int p,int x){while(p<maxB){A[p]+=x;p+=p&-p;}}int sum(int *A,int p){int ans=0;while(p){ans+=A[p];p-=p&-p;}return ans;}void seg_add(int l,int r,int x){add(a,l,-x*(l-1));add(b,l,x);add(a,r+1,x*r);add(b,r+1,-x);}int get(int p){int s1=sum(b,p-1)*(p-1)+sum(a,p-1);int s2=sum(b,p)*(p)+sum(a,p);return s2-s1;}
}B;void update(int v1,int v2,int x){int f1=top[v1],f2=top[v2];while(f1!=f2){if(dep[f1]>dep[f2]) swap(v1,v2),swap(f1,f2);B.seg_add(tw[f2],tw[v2],x);v2=fa[f2],f2=top[v2];}if(dep[v1]>dep[v2]) swap(v1,v2);B.seg_add(tw[v1],tw[v2],x);
}
char r[10];
int main(){freopen("/home/files/CppFiles/in","r",stdin);//freopen("defense.in","r",stdin);//freopen("defense.out","w",stdout);while(cin>>N>>M>>O){dfsn=0;B.clear();for(int i=0;i<maxn;i++)G[i].clear();for(int i=1;i<=N;i++)scanf("%d",&a[i]);for(int i=0;i<M;i++){int u,v;scanf("%d%d",&u,&v);G[u].pb(v);G[v].pb(u);}dfs1(1);dfs2(1);for(int i=1;i<=N;i++)B.seg_add(tw[i],tw[i],a[i]);while(O--){scanf("%s",r);int a,b,c;if(r[0]=='I'){scanf("%d%d%d",&a,&b,&c);update(a,b,c);}else if(r[0]=='D'){scanf("%d%d%d",&a,&b,&c);update(a,b,-c);}else{scanf("%d",&a);printf("%d\n",B.get(tw[a]));}}}return 0;
}

View Code

转载于:https://www.cnblogs.com/Cw-trip/p/4783758.html

SPOJ- QTREE+HDU 3966(树链剖分裸题相关推荐

  1. hdu 3966(树链剖分+线段树区间更新)

    传送门:Problem 3966 https://www.cnblogs.com/violet-acmer/p/9711441.html 学习资料: [1]线段树区间更新:https://blog.c ...

  2. hdu 3966( 树链剖分+点权更新)

    题意:给一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路径上的所有点权值加上K D C1 C2 K:把C1与C2的路径上的所有点权值减去K Q C:查询节点编号为C ...

  3. HDU 3966 树链剖分后线段树维护

    题意: 一棵树, 操作1.$path(a,b)$之间的点权$+k$ 操作2.单点查询 题解: 树链剖分即可,注意代码细节,双向映射 主要是记录一下板子 #include <string.h> ...

  4. 小清的树链剖分10题日志01 树链剖分种果子 有你好果子吃的

    声明:由于本人能力尚不优 故无法做出解释文章 此文仅为自己日记 感谢你的阅读 作为队里的数据结构选手 2019西安邀请赛的E题 竟然在有机时的情况下 想到了线段树log^2的拆位做法 但是题目路径把自 ...

  5. 洛谷P3384 - 树链剖分(树链剖分模板题)

    题目链接 https://www.luogu.org/problemnew/show/P3384 [描述] 树链剖分模板题,记一下板子 #include<bits/stdc++.h> #d ...

  6. hdu 5274(树链剖分)

    解题思路:这道题据说是树链剖分,所以也学习了一下. http://blog.sina.com.cn/s/blog_7a1746820100wp67.html 不同的是这里是点权值,我按照相似的处理方式 ...

  7. 洛谷3384(树链剖分模板题)

    题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...

  8. BZOJ 2243 染色(树链剖分好题)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 7971  Solved: 2990 [Submit][Stat ...

  9. HDU 5405 (树链剖分+线段树)

    Problem Sometimes Naive 题目大意 给你一棵n个节点的树,有点权. 要求支持两种操作: 操作1:更改某个节点的权值. 操作2:给定u,v, 求 Σw[i][j]   i , j ...

最新文章

  1. java 全局变量_Java语言与C语言、C++语言有何差异以及优劣势
  2. 1.6 为什么使用向上转型而不直接创建子类对象?
  3. 数据结构-Hash总结(二)
  4. dueros模拟测试没有请求后台_DuerOS开放平台
  5. 博弈论 ----- Nim游戏
  6. 未雨绸缪,数据保护之NBU介质备份
  7. Topic modeling made just simple enough
  8. spark写入Oracle 报错 java.lang.ArrayIndexOutOfBoundsException: -32423
  9. 插秧诗 - 退步原来是向前
  10. Java语言的跨平台性或Java语言为什么说可以跨平台运行
  11. fgets和gets的区别
  12. 数字图像 - 图像隐写
  13. 记一次配置rewrite和return的经历
  14. 2020年非上海生源应届普通高校毕业生落户材料办理流程及注意事项
  15. android微信群聊功能,微信安卓内测更新,这个群聊功能等了8年
  16. Apple’s ‘Big-A ’ Data Center
  17. 网贷数据爬取及据分析
  18. Web_html十六进制透明颜色码
  19. 长沙旅游攻略!31块的臭豆腐它香吗?
  20. 离散数学c语言实验报告,离散数学数理逻辑C++或C语言实验报告

热门文章

  1. 功能强大的Windows PowerShell
  2. 左值、右值、左值引用、右值引用
  3. latex中bibtex中引用会议和期刊论文时的写法及规则
  4. python 下表溢出
  5. Linux下C++连MySQL数据库
  6. [数据结构] 二叉树基础
  7. 回溯法——打印子集树
  8. 智能车大赛信标组_第十五届全国大学生智能汽车竞赛在南京信息工程大学圆满闭幕...
  9. 关于AppCompatDelegate的使用
  10. Java中input与output_java中的Io(input与output)操作总结(四)