【COGS1672】难存的情缘
【题目描述】
一天机房的夜晚,无数人在MC里奋斗着。。。
大家都知道矿产对于MC来说是多么的重要,但由于矿越挖越少,勇士们不得不跑到更远的地方挖矿,但这样路途上就会花费相当大的时间,导致挖矿效率底下。
cjj提议修一条铁路,大家一致同意。
大家都被CH分配了一些任务:
zjmfrank2012负责绘制出一个矿道地图,这个地图包括家(当然这也是一个矿,毕竟不把家掏空我们是不会走的),和无数个矿,所以大家应该可以想出这是一个无向无环图,也就是一棵树。
Digital_T和cstdio负责铺铁路。。所以这里没他们什么事,两位可以劳作去了。
这个时候song526210932和RMB突然发现有的矿道会刷怪,并且怪的数量会发生变化。作为采矿主力,他们想知道从一个矿到另一个矿的路上哪一段会最困难。。。(困难值用zjm的死亡次数表示)。
【输入格式】
输入文件的第一行有一个整数N,代表矿的数量。矿的编号是1到N。
接下来N-1行每行有三个整数a,b,c,代表第i号矿和第j号矿之间有一条路,在初始时这条路的困难值为c。
接下来有若干行,每行是“CHANGE i ti”或者“QUERY a b”,前者代表把第i条路(路按所给顺序从1到M编号)的困难值修改为ti,后者代表查询a到b所经过的道路中的最大困难值。
输入数据以一行“DONE”结束。
【输出格式】
对每个“QUERY”操作,输出一行一个正整数,即最大困难值。
【分析】
实在是让人无语的背景改变,顺便膜拜一下梦迪神牛Orzzzzzzzz。
最基本的树链剖分。
1 #include <cstring> 2 #include <cmath> 3 #include <cstdio> 4 #include <iostream> 5 #include <vector> 6 const int maxn=100000+1000; 7 using namespace std; 8 struct Edge 9 { 10 int to;//所指向的 11 int num;//记录边的编号 12 }; 13 int d[maxn][3],edge=0,n,root;//用来记录边的属性 14 int siz[maxn],son[maxn];//子树大小和重儿子 15 int fa[maxn],dep[maxn],z;//父亲和深度 16 int w[maxn],top[maxn],tree[maxn]; 17 char str[55]; 18 vector<Edge>map[maxn]; 19 20 inline void init(); 21 inline void work(); 22 inline void dfs(int u);//第一次DFS 23 inline void addEdge(int u,int v);//加边 24 inline void make_tree(int u,int tp);//第二次DFS 25 inline void update(int root,int l,int r,int num,int c);//c是变更值 26 inline int read();//读入函数 27 inline int find(int a,int b); 28 inline int maxi(int root,int l,int r,int l1,int l2); 29 30 31 inline void addEdge(int u,int v) 32 { 33 edge++; 34 map[u].push_back((Edge){v,edge}); 35 } 36 inline void dfs(int u)//第一次dfs 37 { 38 int i; 39 siz[u]=1; 40 son[u]=0; 41 for (i=0;i<map[u].size();i++) 42 { 43 int v=map[u][i].to; 44 if (v!=fa[u]) 45 { 46 fa[v]=u;//更新父亲 47 dep[v]=dep[u]+1;//更新深度 48 dfs(v); 49 if (siz[v]>siz[son[u]]) son[u]=v; 50 siz[u]+=siz[v]; 51 } 52 } 53 } 54 //建树操作 55 inline void make_tree(int u,int tp) 56 { 57 int i; 58 w[u]=++z; 59 top[u]=tp; 60 if (son[u]!=0) make_tree(son[u],top[u]);//优先走重儿子 61 for (i=0;i<map[u].size();i++) 62 { 63 int v=map[u][i].to; 64 if (v!=son[u] && v!=fa[u]) 65 make_tree(v,v); 66 } 67 } 68 //修改操作 69 inline void update(int root,int l,int r,int num,int c) 70 { 71 if (num>r || num<l) return; 72 if (l==r) {tree[root]=c;return;} 73 int mid=(l+r)/2; 74 //递归修改 75 update(root*2,l,mid,num,c); 76 update(root*2+1,mid+1,r,num,c); 77 tree[root]=max(tree[root*2],tree[root*2+1]); 78 } 79 inline void init() 80 { 81 int i; 82 scanf("%d",&n); 83 root=(1+n)/2;//随机根 84 fa[root]=z=dep[root]=edge=0; 85 memset(d,0,sizeof(d)); 86 memset(tree,0,sizeof(tree)); 87 for (i=1;i<n;i++) 88 { 89 int u,v,w; 90 scanf("%d%d%d",&u,&v,&w); 91 d[i][0]=u;d[i][1]=v;d[i][2]=w; 92 addEdge(u,v);//加无向边 93 addEdge(v,u); 94 } 95 dfs(root);//第一次 96 make_tree(root,root); 97 for (i=1;i<n;i++) 98 { 99 if (dep[d[i][0]]>dep[d[i][1]]) swap(d[i][0],d[i][1]);//交换 100 update(1,1,z,w[d[i][1]],d[i][2]);//开始加边 101 } 102 return; 103 } 104 inline int read() 105 { 106 scanf("%s",str); 107 if (str[0]=='D') 108 return 0; 109 //printf("%s\n",str); 110 return 1; 111 } 112 inline int maxi(int root,int l,int r,int l1,int r1) 113 { 114 if (l1>r || r1<l) return 0;//边界条件 115 if (l1<=l && r<=r1) return tree[root]; 116 int mid=(l+r)/2; 117 return max(maxi(root*2,l,mid,l1,r1),maxi(root*2+1,mid+1,r,l1,r1)); 118 } 119 //进行从a到b的询问 120 inline int find(int a,int b) 121 { 122 int f1=top[a],f2=top[b],temp=0; 123 while (f1!=f2)//LCA 124 { 125 if (dep[f1]<dep[f2])//统一深度 126 { 127 swap(f1,f2); 128 swap(a,b); 129 } 130 temp=max(temp,maxi(1,1,z,w[f1],w[a])); 131 a=fa[f1];f1=top[a];//向上传递 132 } 133 if (a==b) return temp; 134 if (dep[a]>dep[b]) swap(a,b); 135 return max(temp,maxi(1,1,z,w[son[a]],w[b])); 136 } 137 inline void work() 138 { 139 int a,b; 140 while (read()) 141 { 142 scanf("%d%d",&a,&b); 143 if (str[0]=='Q') printf("%d\n",find(a,b)); 144 else update(1,1,z,w[d[a][1]],b); 145 } 146 return; 147 } 148 int main() 149 { 150 //文件操作 151 freopen("qtree.in","r",stdin); 152 freopen("qtree.out","w",stdout); 153 init();//初始化 154 work(); 155 return 0; 156 }